@@ -61,9 +61,9 @@ function compile_products(recipe::ImageRecipe)
6161 recipe. add_ccallables = true
6262 end
6363 # Default: disable signal handlers and limit to single thread for shared libraries
64- if recipe. output_type == " --output-lib" && isempty (recipe . jl_options)
65- recipe. jl_options[ " handle-signals" ] = " no"
66- recipe. jl_options[ " threads" ] = " 1"
64+ if recipe. output_type == " --output-lib"
65+ get! ( recipe. jl_options, " handle-signals" , " no" )
66+ get! ( recipe. jl_options, " threads" , " 1" )
6767 end
6868 if recipe. cpu_target === nothing
6969 recipe. cpu_target = get (ENV ," JULIA_CPU_TARGET" , nothing )
@@ -214,79 +214,16 @@ function _validate_jl_options(jl_options::Dict{String,String})
214214end
215215
216216"""
217- Parse `--jl-option handle-signals=yes|no` into C assignments.
218- Mirrors Julia's `--handle-signals` parsing in `jloptions.c`.
219- """
220- function _emit_handle_signals (io:: IO , value:: String )
221- if value == " yes"
222- println (io, " opts->handle_signals = JL_OPTIONS_HANDLE_SIGNALS_ON;" )
223- elseif value == " no"
224- println (io, " opts->handle_signals = JL_OPTIONS_HANDLE_SIGNALS_OFF;" )
225- else
226- error (" Invalid value for handle-signals: \" $value \" . Expected \" yes\" or \" no\" ." )
227- end
228- end
229-
230- """
231- Parse `--jl-option threads=N[,M]` into C assignments.
232- Mirrors Julia's `--threads` / `-t` parsing in `jloptions.c`:
233- - `N` → N threads in default pool; if N==1, 1 pool; else 2 pools (+ 1 interactive)
234- - `N,M` → N default + M interactive; if M==0, 1 pool; else 2 pools
235- - `N,auto` → N default + 1 interactive, 2 pools
236-
237- Does not support `auto` for N (libraries should specify a concrete thread count).
238- """
239- function _emit_threads (io:: IO , value:: String )
240- parts = split (value, ' ,' ; limit= 2 )
241- nthreads_str = parts[1 ]
242- nthreads_str == " auto" && error (" \" auto\" is not supported for threads in --jl-option; specify a concrete count." )
243- nthreads = tryparse (Int, nthreads_str)
244- nthreads === nothing && error (" Invalid thread count: \" $nthreads_str \" " )
245- nthreads < 1 && error (" Thread count must be >= 1, got $nthreads " )
246-
247- if length (parts) == 2
248- # N,M or N,auto
249- ipart = parts[2 ]
250- if ipart == " auto"
251- nthreadsi = 1
252- else
253- nthreadsi = tryparse (Int, ipart)
254- nthreadsi === nothing && error (" Invalid interactive thread count: \" $ipart \" " )
255- nthreadsi < 0 && error (" Interactive thread count must be >= 0, got $nthreadsi " )
256- end
257- elseif nthreads == 1
258- # Like Julia: 1 thread → no interactive pool
259- nthreadsi = 0
260- else
261- # Like Julia: N>1 → add 1 interactive thread
262- nthreadsi = 1
263- end
264-
265- nthreadpools = nthreadsi == 0 ? 1 : 2
266- total = nthreads + nthreadsi
267-
268- println (io, " opts->nthreads = $total ;" )
269- println (io, " opts->nthreadpools = $nthreadpools ;" )
270- println (io, " {" )
271- println (io, " int16_t *ntpp = (int16_t *)malloc($nthreadpools * sizeof(int16_t));" )
272- println (io, " if (ntpp) {" )
273- println (io, " ntpp[0] = (int16_t)$nthreads ;" )
274- if nthreadpools == 2
275- println (io, " ntpp[1] = (int16_t)$nthreadsi ;" )
276- end
277- println (io, " opts->nthreads_per_pool = ntpp;" )
278- println (io, " }" )
279- println (io, " }" )
280- end
281-
282- """
283- Generate and compile a C shim that overrides `jl_options` fields via an
284- `__attribute__((constructor))`.
217+ Generate and compile a C shim that calls `jl_parse_opts` with a synthetic
218+ argv in an `__attribute__((constructor))`.
285219
286220The boilerplate C code lives in `scripts/juliac-jl-options-shim.c` and
287- `#include`s a generated `juliac-jl-options-body.h` containing just the
288- option assignments. See the shim source for how `jl_options` is resolved
289- on each platform.
221+ `#include`s a generated `juliac-jl-options-body.h` containing the argv
222+ string literals.
223+
224+ After compilation, links the shim into a trivial executable and runs it
225+ to validate that `jl_parse_opts` accepts the options. This catches invalid
226+ values at compile time rather than at load time.
290227
291228Returns the path to the compiled object file.
292229"""
@@ -297,14 +234,11 @@ function _compile_jl_options_shim(jl_options::Dict{String,String}; verbose::Bool
297234 shim_src = joinpath (JuliaC. SCRIPTS_DIR, " juliac-jl-options-shim.c" )
298235 body_hdr = joinpath (tmpdir, " juliac-jl-options-body.h" )
299236 init_obj = joinpath (tmpdir, " juliac-jl-options-init.o" )
300- # Generate only the option-assignment body
237+ # Generate argv entries for jl_parse_opts
301238 open (body_hdr, " w" ) do io
302- println (io, " /* Generated by JuliaC — jl_options field assignments */" )
303- if haskey (jl_options, " handle-signals" )
304- _emit_handle_signals (io, jl_options[" handle-signals" ])
305- end
306- if haskey (jl_options, " threads" )
307- _emit_threads (io, jl_options[" threads" ])
239+ println (io, " /* Generated by JuliaC — jl_parse_opts argv entries */" )
240+ for (key, value) in jl_options
241+ println (io, " \" --$(key) =$(value) \" ," )
308242 end
309243 end
310244 verbose && println (" Generated jl_options body: $body_hdr " )
@@ -320,5 +254,16 @@ function _compile_jl_options_shim(jl_options::Dict{String,String}; verbose::Bool
320254 catch e
321255 error (" jl_options init shim compilation failed: " , e)
322256 end
257+ # Validate by running julia with the same flags.
258+ julia_bin = joinpath (Sys. BINDIR, " julia" )
259+ validate_cmd = ` $julia_bin `
260+ for (key, value) in jl_options
261+ validate_cmd = ` $validate_cmd --$(key) =$(value) `
262+ end
263+ validate_cmd = ` $validate_cmd -e ""`
264+ verbose && println (" Validating jl_options: $validate_cmd " )
265+ if ! success (pipeline (validate_cmd; stdout = devnull , stderr ))
266+ error (" Invalid --jl-option values. Check that option values match Julia CLI syntax (e.g. --handle-signals=yes|no, --threads=N[,M])." )
267+ end
323268 return init_obj
324269end
0 commit comments