# Experiments trying to use ArgMacros.jl with juliac

**URL:** https://discourse.julialang.org/t/experiments-trying-to-use-argmacros-jl-with-juliac/125442
**Category:** General Usage
**Tags:** cli, juliac
**Created:** [February 1, 2025, 1:42am UTC](https://discourse.julialang.org/t/experiments-trying-to-use-argmacros-jl-with-juliac/125442 "2025-02-01T01:42:21Z")
**Posts on this page:** 1
**Page:** 1

<div class="post-metadata">

### Author: ![BenjaminDoran](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/benjamindoran/32/34587_2.png) [@BenjaminDoran](https://discourse.julialang.org/u/BenjaminDoran)
#### Post date: [February 1, 2025, 1:42am UTC](https://discourse.julialang.org/t/experiments-trying-to-use-argmacros-jl-with-juliac/125442/1 "2025-02-01T01:42:21Z")

</div>

So, I was playing around with argument parsing in the context of the experimental juliac compilation and trying to use ArgMacros.jl since I have enjoyed its syntax for making CLI scripts in the past.

A couple weeks ago I compiled this script.

```julia
using ArgMacros

function parseargs(ARGS)
    args = @tuplearguments begin
        @argumentdefault Int 3 defaultnum "--default"
        @argumentoptional Int mynumber "--number"
        @argumentflag isdone "-f"
        @argumentflag verbose "-v" "--verbose"
    end
    return args
end

function (@main)(ARGS)
    args = parseargs(ARGS) # segfaults only with mistaken usage

    println(Core.stdout, args.defaultnum)
    println(Core.stdout, args.mynumber)
    println(Core.stdout, args.isdone)
    println(Core.stdout, args.verbose)
    return 0
end

# pattern copied from https://github.com/MasonProtter/juliac-bench
Base.@ccallable function main(argc::Cint, argv::Ptr{Ptr{UInt8}})::Cint
    args = Vector{String}(undef, argc - 1)
    for i = 2:argc
        argptr = unsafe_load(argv, i)
        arg = unsafe_string(argptr)
        args[i-1] = arg
    end
    main(args)
end
Base.Experimental.entrypoint(main, (Cint, Ptr{Ptr{UInt8}}))

```

It compiled. And it would work when passing arguments as expected, though it would segfault if any unexpected arguments or flags were passed. My impression is that it was trying to generate the usage documentation but during the compilation a needed function had been trimmed out. I’m assuming because the compiler can’t see the error case?

> **initial segfault**
>
> ```bash
> % ./builds/testexe --number 5 --unexpected
> 
> [50862] signal 11 (1): Segmentation fault: 11
> in expression starting at none:0
> jl_lookup_generic_ at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-grannysmith-C07ZQ07FJYVY.0/build/default-grannysmith-C07ZQ07FJYVY-0/julialang/julia-master/src/gf.c:3480 [inlined]
> ijl_apply_generic at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-grannysmith-C07ZQ07FJYVY.0/build/default-grannysmith-C07ZQ07FJYVY-0/julialang/julia-master/src/gf.c:3553
> jl_apply at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-grannysmith-C07ZQ07FJYVY.0/build/default-grannysmith-C07ZQ07FJYVY-0/julialang/julia-master/src/./julia.h:2244 [inlined]
> jl_type_infer at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-grannysmith-C07ZQ07FJYVY.0/build/default-grannysmith-C07ZQ07FJYVY-0/julialang/julia-master/src/gf.c:395
> jl_compile_method_internal at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-grannysmith-C07ZQ07FJYVY.0/build/default-grannysmith-C07ZQ07FJYVY-0/julialang/julia-master/src/gf.c:2887
> _jl_invoke at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-grannysmith-C07ZQ07FJYVY.0/build/default-grannysmith-C07ZQ07FJYVY-0/julialang/julia-master/src/gf.c:3361 [inlined]
> ijl_apply_generic at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-grannysmith-C07ZQ07FJYVY.0/build/default-grannysmith-C07ZQ07FJYVY-0/julialang/julia-master/src/gf.c:3557
> println at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
> _quit_try_help at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
> parseargs at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
> main at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
> main at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
> main at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
> start at /usr/lib/dyld (unknown line)
> Allocations: 2 (Pool: 2; Big: 0); GC: 0
> zsh: segmentation fault ./builds/testexe --number 5 --unexpected
> 
> ```

I just updated to the latest nightly and it still compiles, but now it errors in all cases with

```bash
fatal: error thrown and no exception handler available.
Core.MethodError(f=Core.Int64, args=(3,), world=0x0000000000008e45)
jl_method_error_bare at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-macmini-x64-6.0/build/default-macmini-x64-6-0/julialang/julia-master/src/gf.c:2508
jl_method_error at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-macmini-x64-6.0/build/default-macmini-x64-6-0/julialang/julia-master/src/gf.c:2526
jl_lookup_generic_ at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-macmini-x64-6.0/build/default-macmini-x64-6-0/julialang/julia-master/src/gf.c:3644 [inlined]
ijl_apply_generic at /Users/julia/.julia/scratchspaces/a66863c6-20e8-4ff4-8a62-49f30b1f605e/agent-cache/default-macmini-x64-6.0/build/default-macmini-x64-6-0/julialang/julia-master/src/gf.c:3670
_converttypeNOT. at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
parseargs at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
main at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
main at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
main at /Users/ben/projects/sandbox/julia_testscripts/builds/testexe (unknown line)
start at /usr/lib/dyld (unknown line)
./builds/testexe --number 5 0.59s user 0.11s system 108% cpu 0.645 total

```

Obviously juliac is still experimental, so I am not expecting any kind of immediate solution here. And I also understand if it is too early to comment on some of these questions.

That said, my questions are

1. What suggestions are for how to get ArgMacros.jl working with juliac? (This seemed easier a week or two ago, when it was only erroring on unexpected flags)
2. does anyone know what changed in juliac to change the scripts behavior?
3. Are there broader thoughts or plans for making argument parsing easier with juliac?
4. Are there plans to unify the scripting entry point `(@main)(ARGS)` with the `Base.Experimental.entrypoint(main, (Cint, Ptr{Ptr{UInt8}}))`?

For those interested the @tuplearguments macro expands to:

> **@tuplearguments macro expansion**
>
> ```julia
> julia> @macroexpand @tuplearguments begin
> @argumentdefault Int 3 defaultnum "--default"
> @argumentoptional Int mynumber "--number"
> @argumentflag isdone "-f"
> @argumentflag verbose "-v" "--verbose"
> end
> :(let
> begin
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:32 =#
> var"#31#splitargs" = ArgMacros._split_arguments(ARGS)
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:33 =#
> var"#32#allowextraargs" = false
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:35 =#
> ArgMacros._help_check(var"#31#splitargs", $(Expr(:copyast, :($(QuoteNode(quote
> #= REPL[1]:2 =#
> #= REPL[1]:2 =# @argumentdefault Int 3 defaultnum "--default"
> #= REPL[1]:3 =#
> #= REPL[1]:3 =# @argumentoptional Int mynumber "--number"
> #= REPL[1]:4 =#
> #= REPL[1]:4 =# @argumentflag isdone "-f"
> #= REPL[1]:5 =#
> #= REPL[1]:5 =# @argumentflag verbose "-v" "--verbose"
> end))))))
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:37 =#
> begin
> #= REPL[1]:2 =#
> begin
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:213 =#
> var"#34#potential_val"::ArgMacros.Union{ArgMacros.String, ArgMacros.Nothing} = ArgMacros._pop_argval!(var"#31#splitargs", [("--default",)...])
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:215 =#
> local defaultnum::Int = ArgMacros._converttype!(ArgMacros.Int, ArgMacros.something(var"#34#potential_val", 3), "--default")
> end
> #= REPL[1]:3 =#
> begin
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:240 =#
> var"#36#potential_val"::ArgMacros.Union{ArgMacros.String, ArgMacros.Nothing} = ArgMacros._pop_argval!(var"#31#splitargs", [("--number",)...])
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:242 =#
> local mynumber::(Union){Int, Nothing} = if ArgMacros.isnothing(var"#36#potential_val")
> ArgMacros.nothing
> else
> ArgMacros._converttype!(ArgMacros.Int, var"#36#potential_val", "--number")
> end
> end
> #= REPL[1]:4 =#
> begin
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:267 =#
> local isdone::Bool = ArgMacros._pop_flag!(var"#31#splitargs", [("-f",)...])
> end
> #= REPL[1]:5 =#
> begin
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:267 =#
> local verbose::Bool = ArgMacros._pop_flag!(var"#31#splitargs", [("-v", "--verbose")...])
> end
> end
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:39 =#
> if !var"#32#allowextraargs" && !(ArgMacros.isempty(var"#31#splitargs"))
> #= /Users/ben/.julia/packages/ArgMacros/JJu6G/src/macros.jl:40 =#
> ArgMacros._quit_try_help("Too many or unrecognized arguments provided")
> end
> end
> (defaultnum = defaultnum, mynumber = mynumber, isdone = isdone, verbose = verbose)
> end)
> 
> ```
