@@ -349,12 +349,30 @@ fn sanitized_utf8_str_visible_length_fn() string {
349349
350350fn (mut b Builder) compile_cleanc_executable (output_name string , cc string , cc_flags string , cc_link_flags string , error_limit_flag string , mut sw time.StopWatch) {
351351 cc_start := sw.elapsed ()
352- // Non-cached path: compile and link in one step, so include both compile and link flags.
353- mut all_flags := cc_flags
352+ if b.pref.is_shared_lib {
353+ // Shared library: compile with -shared -fPIC -undefined dynamic_lookup
354+ // Use -fvisibility=hidden so only explicitly exported (impl_live_*) symbols
355+ // are visible. All other functions become hidden, causing the dylib to
356+ // resolve them from the host executable at load time.
357+ mut cc_cmd := '${cc } ${cc_flags } -shared -fPIC -fvisibility=hidden -undefined dynamic_lookup -w -Wno-incompatible-function-pointer-types "${staged_c_file }"'
358+ if cc_link_flags.len > 0 {
359+ cc_cmd + = ' -x none ${cc_link_flags }'
360+ }
361+ cc_cmd + = ' -o "${output_name }"${error_limit_flag }'
362+ run_cc_cmd_or_exit (cc_cmd, 'shared lib compilation' , b.pref.show_cc)
363+ print_time ('CC (shared)' , time.Duration (sw.elapsed () - cc_start))
364+ println ('[*] Compiled shared library ${output_name }' )
365+ return
366+ }
367+ // Non-cached path: compile and link in one step.
368+ // Place link flags (which may include .o files) AFTER the source file.
369+ // Use `-x none` to reset the language before .o files, since -x objective-c
370+ // would cause cc to treat .o files as source code.
371+ mut cc_cmd := '${cc } ${cc_flags } -w -Wno-incompatible-function-pointer-types "${staged_c_file }"'
354372 if cc_link_flags.len > 0 {
355- all_flags + = ' ${cc_link_flags }'
373+ cc_cmd + = ' -x none ${cc_link_flags }'
356374 }
357- cc_cmd : = '${ cc } ${ all_flags } -w "${ staged_c_file }" -o "${output_name }"${error_limit_flag }'
375+ cc_cmd + = ' -o "${output_name }"${error_limit_flag }'
358376 run_cc_cmd_or_exit (cc_cmd, 'C compilation' , b.pref.show_cc)
359377 print_time ('CC' , time.Duration (sw.elapsed () - cc_start))
360378
@@ -924,7 +942,7 @@ fn (mut b Builder) gen_cleanc_with_cached_core(output_name string, cc string, cc
924942
925943 cc_start := sw.elapsed ()
926944 main_obj := staged_main_obj_file
927- compile_main_cmd := '${main_cc } ${main_cc_flags } -w -c "${main_c_file }" -o "${main_obj }"${error_limit_flag }'
945+ compile_main_cmd := '${main_cc } ${main_cc_flags } -w -Wno-incompatible-function-pointer-types - c "${main_c_file }" -o "${main_obj }"${error_limit_flag }'
928946 main_fell_back := run_cc_cmd_or_exit (compile_main_cmd, 'C compilation' , b.pref.show_cc)
929947 if main_fell_back && main_cc.contains ('tcc' ) {
930948 // TCC failed on main.c but cached .o files are ELF (from TCC).
@@ -936,7 +954,11 @@ fn (mut b Builder) gen_cleanc_with_cached_core(output_name string, cc string, cc
936954 }
937955 return false
938956 }
939- mut link_cmd := '${main_cc } ${main_cc_flags } -w "${main_obj }" "${builtin_obj }"'
957+ // Strip -c and -x flags from link command since we're linking, not compiling.
958+ // -x objective-c would cause cc to treat .o files as source code.
959+ mut link_flags := main_cc_flags.replace ('-x objective-c' , '' ).replace ('-x c' , '' ).replace (' -c ' ,
960+ ' ' )
961+ mut link_cmd := '${main_cc } ${link_flags } -w "${main_obj }" "${builtin_obj }"'
940962 if vlib_obj.len > 0 {
941963 link_cmd + = ' "${vlib_obj }"'
942964 }
@@ -1070,7 +1092,7 @@ fn (mut b Builder) ensure_cached_module_object(cache_dir string, cache_name stri
10701092 }
10711093 os.write_file (c_path, module_source)!
10721094
1073- compile_cmd := '${cc } ${cc_flags } -w -c "${c_path }" -o "${obj_path }"${error_limit_flag }'
1095+ compile_cmd := '${cc } ${cc_flags } -w -Wno-incompatible-function-pointer-types - c "${c_path }" -o "${obj_path }"${error_limit_flag }'
10741096 run_cc_cmd_or_exit (compile_cmd, 'C compilation' , b.pref.show_cc)
10751097 os.write_file (stamp_path, expected_stamp)!
10761098 return obj_path
@@ -1235,6 +1257,17 @@ fn flag_references_missing_file(flag string) bool {
12351257 || clean.ends_with ('.dylib' ) || clean.ends_with ('.m' ) || clean.ends_with ('.c' ) {
12361258 if os.is_abs_path (clean) || clean.starts_with ('./' ) || clean.starts_with ('../' ) {
12371259 if ! os.exists (clean) {
1260+ // For .o files, try to build from corresponding .c file
1261+ if clean.ends_with ('.o' ) {
1262+ c_file := clean[..clean.len - 2 ] + '.c'
1263+ if os.exists (c_file) {
1264+ compile_cmd := 'cc -c -w -O2 "${c_file }" -o "${clean }"'
1265+ res := os.execute (compile_cmd)
1266+ if res.exit_code == 0 {
1267+ continue // successfully compiled, not missing
1268+ }
1269+ }
1270+ }
12381271 return true
12391272 }
12401273 }
@@ -1479,10 +1512,52 @@ fn (mut b Builder) gen_native(backend_arch pref.Arch) {
14791512 print_time ('SSA Build' , time.Duration (native_sw.elapsed () - stage_start))
14801513
14811514 stage_start = native_sw.elapsed ()
1482- ssa_optimize.optimize (mut mod)
1515+ if b.pref.no_optimize {
1516+ eprintln (' opt: skipped (-O0)' )
1517+ } else {
1518+ ssa_optimize.optimize (mut mod)
1519+ }
14831520 print_time ('SSA Optimize' , time.Duration (native_sw.elapsed () - stage_start))
14841521 $if debug {
1485- ssa_optimize.verify_and_panic (mod, 'full optimization' )
1522+ if ! b.pref.no_optimize {
1523+ ssa_optimize.verify_and_panic (mod, 'full optimization' )
1524+ }
1525+ }
1526+
1527+ // Post-optimization SSA dump for debugging
1528+ dump_fn_name := os.getenv ('V2_DUMP_OPT_SSA' )
1529+ if dump_fn_name.len > 0 {
1530+ for func in mod.funcs {
1531+ if func.name == dump_fn_name {
1532+ eprintln ('=== POST-OPT SSA DUMP: ${func .name } ===' )
1533+ eprintln (' params: ${func .params }' )
1534+ for pi, pid in func.params {
1535+ pval := mod.values[pid]
1536+ eprintln (' param[${pi }]: v${pid } kind=${pval .kind } name=`${pval .name }` typ=${pval .typ }' )
1537+ }
1538+ for blk_id in func.blocks {
1539+ blk := mod.blocks[blk_id]
1540+ eprintln (' block ${blk_id } (${blk .name }):' )
1541+ for dval_id in blk.instrs {
1542+ dval := mod.values[dval_id]
1543+ if dval.kind != .instruction {
1544+ continue
1545+ }
1546+ dinstr := mod.instrs[dval.index]
1547+ mut ops_str := ''
1548+ for oi, op_id in dinstr.operands {
1549+ op_v := mod.values[op_id]
1550+ ops_str + = 'v${op_id }(${op_v .kind }:${op_v .name })'
1551+ if oi < dinstr.operands.len - 1 {
1552+ ops_str + = ', '
1553+ }
1554+ }
1555+ eprintln (' v${dval_id }: ${dinstr .op } [${ops_str }] typ=${dval .typ }' )
1556+ }
1557+ }
1558+ eprintln ('=== END POST-OPT SSA DUMP ===' )
1559+ }
1560+ }
14861561 }
14871562
14881563 stage_start = native_sw.elapsed ()
0 commit comments