Skip to content

Commit 3bb7bc1

Browse files
committed
Allow tcc and cc to find multiarch libs (like -lm); fix issues with shared .
1 parent 8af66b1 commit 3bb7bc1

3 files changed

Lines changed: 118 additions & 3 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,8 @@ Operational `libtcc` runtime location/options remain configurable:
320320
- `ME_DSL_JIT_LIBTCC_PATH=/path/to/libtcc.{so,dylib}`: Override runtime library path used for `libtcc` loading.
321321
- `ME_DSL_JIT_TCC_LIB_PATH=/path/to/tcc/libdir`: Override `tcc_set_lib_path()` directory (mainly for custom/legacy `libtcc` layouts).
322322
- `ME_DSL_JIT_TCC_OPTIONS="..."`: Extra options passed to `tcc_set_options()`.
323+
- On Linux, the libtcc JIT automatically appends common multiarch library directories
324+
(for example `/usr/lib/x86_64-linux-gnu`) to help `-lm` resolve without extra flags.
323325
324326
Build-time note:
325327

doc/dsl-usage.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,8 @@ Notes:
116116
- With `# me:compiler=cc`, runtime uses `CC` (default: `cc`) to select the compiler executable.
117117
- With `# me:compiler=cc`, runtime also honors `CFLAGS`.
118118
- Build option `MINIEXPR_ENABLE_TCC_JIT=OFF` disables TCC-based JIT backends; on Linux/macOS, the separate `# me:compiler=cc` runtime path may still be available.
119+
- On Linux, the libtcc JIT automatically appends common multiarch library directories
120+
(for example `/usr/lib/x86_64-linux-gnu`) to help `-lm` resolve without extra flags.
119121
- If the selected backend is unavailable at runtime, miniexpr falls back to interpreter execution.
120122
121123
### Temporary Variables

src/miniexpr.c

Lines changed: 114 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4176,7 +4176,11 @@ static bool dsl_jit_get_cache_dir(char *out, size_t out_size) {
41764176
}
41774177
const char *tmpdir = getenv("TMPDIR");
41784178
if (!tmpdir || tmpdir[0] == '\0') {
4179-
tmpdir = "/tmp";
4179+
/* Avoid cross-user permission conflicts when TMPDIR is not set. */
4180+
if (snprintf(out, out_size, "/tmp/miniexpr-jit-%lu", (unsigned long)getuid()) >= (int)out_size) {
4181+
return false;
4182+
}
4183+
return dsl_jit_ensure_dir(out);
41804184
}
41814185
if (snprintf(out, out_size, "%s/miniexpr-jit", tmpdir) >= (int)out_size) {
41824186
return false;
@@ -4322,6 +4326,7 @@ typedef int (*me_tcc_compile_string_fn)(me_tcc_state *s, const char *buf);
43224326
typedef int (*me_tcc_relocate_fn)(me_tcc_state *s);
43234327
typedef void *(*me_tcc_get_symbol_fn)(me_tcc_state *s, const char *name);
43244328
typedef int (*me_tcc_set_options_fn)(me_tcc_state *s, const char *str);
4329+
typedef int (*me_tcc_add_library_path_fn)(me_tcc_state *s, const char *path);
43254330
typedef int (*me_tcc_add_library_fn)(me_tcc_state *s, const char *libraryname);
43264331
typedef int (*me_tcc_add_symbol_fn)(me_tcc_state *s, const char *name, const void *val);
43274332
typedef void (*me_tcc_set_lib_path_fn)(me_tcc_state *s, const char *path);
@@ -4337,6 +4342,7 @@ typedef struct {
43374342
me_tcc_relocate_fn tcc_relocate_fn;
43384343
me_tcc_get_symbol_fn tcc_get_symbol_fn;
43394344
me_tcc_set_options_fn tcc_set_options_fn;
4345+
me_tcc_add_library_path_fn tcc_add_library_path_fn;
43404346
me_tcc_add_library_fn tcc_add_library_fn;
43414347
me_tcc_add_symbol_fn tcc_add_symbol_fn;
43424348
me_tcc_set_lib_path_fn tcc_set_lib_path_fn;
@@ -4514,6 +4520,49 @@ static bool dsl_jit_libtcc_runtime_dir(char *out, size_t out_size) {
45144520
return dsl_jit_path_dirname(module_path, out, out_size);
45154521
}
45164522

4523+
static void dsl_jit_libtcc_add_library_path_if_exists(me_tcc_state *state, const char *path) {
4524+
if (!state || !g_dsl_tcc_api.tcc_add_library_path_fn || !path || path[0] == '\0') {
4525+
return;
4526+
}
4527+
struct stat st;
4528+
if (stat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
4529+
(void)g_dsl_tcc_api.tcc_add_library_path_fn(state, path);
4530+
}
4531+
}
4532+
4533+
static void dsl_jit_libtcc_add_multiarch_paths(me_tcc_state *state) {
4534+
#if defined(__linux__)
4535+
if (!state || !g_dsl_tcc_api.tcc_add_library_path_fn) {
4536+
return;
4537+
}
4538+
const char *paths[] = {
4539+
#if defined(__x86_64__) || defined(__amd64__)
4540+
"/usr/lib/x86_64-linux-gnu", "/lib/x86_64-linux-gnu",
4541+
#elif defined(__aarch64__)
4542+
"/usr/lib/aarch64-linux-gnu", "/lib/aarch64-linux-gnu",
4543+
#elif defined(__arm__)
4544+
"/usr/lib/arm-linux-gnueabihf", "/lib/arm-linux-gnueabihf",
4545+
"/usr/lib/arm-linux-gnueabi", "/lib/arm-linux-gnueabi",
4546+
#elif defined(__riscv) && (__riscv_xlen == 64)
4547+
"/usr/lib/riscv64-linux-gnu", "/lib/riscv64-linux-gnu",
4548+
#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)
4549+
"/usr/lib/powerpc64le-linux-gnu", "/lib/powerpc64le-linux-gnu",
4550+
#elif defined(__s390x__)
4551+
"/usr/lib/s390x-linux-gnu", "/lib/s390x-linux-gnu",
4552+
#elif defined(__i386__)
4553+
"/usr/lib/i386-linux-gnu", "/lib/i386-linux-gnu",
4554+
#endif
4555+
"/usr/lib64", "/lib64",
4556+
NULL
4557+
};
4558+
for (int i = 0; paths[i]; i++) {
4559+
dsl_jit_libtcc_add_library_path_if_exists(state, paths[i]);
4560+
}
4561+
#else
4562+
(void)state;
4563+
#endif
4564+
}
4565+
45174566
static double dsl_jit_bridge_apply_unary_f64(void (*fn)(const double *, double *, int), double x) {
45184567
double in_buf[1];
45194568
double out_buf[1];
@@ -5392,6 +5441,7 @@ static bool dsl_jit_libtcc_load_api(void) {
53925441
#undef ME_LOAD_TCC_SYM
53935442

53945443
g_dsl_tcc_api.tcc_set_options_fn = (me_tcc_set_options_fn)dsl_jit_dynlib_symbol(handle, "tcc_set_options");
5444+
g_dsl_tcc_api.tcc_add_library_path_fn = (me_tcc_add_library_path_fn)dsl_jit_dynlib_symbol(handle, "tcc_add_library_path");
53955445
g_dsl_tcc_api.tcc_add_library_fn = (me_tcc_add_library_fn)dsl_jit_dynlib_symbol(handle, "tcc_add_library");
53965446
g_dsl_tcc_api.tcc_add_symbol_fn = (me_tcc_add_symbol_fn)dsl_jit_dynlib_symbol(handle, "tcc_add_symbol");
53975447
g_dsl_tcc_api.tcc_set_lib_path_fn = (me_tcc_set_lib_path_fn)dsl_jit_dynlib_symbol(handle, "tcc_set_lib_path");
@@ -5446,6 +5496,7 @@ static bool dsl_jit_compile_libtcc_in_memory(me_dsl_compiled_program *program) {
54465496
"tcc_set_output_type failed");
54475497
return false;
54485498
}
5499+
dsl_jit_libtcc_add_multiarch_paths(state);
54495500
#if !defined(__APPLE__) && !defined(_WIN32) && !defined(_WIN64)
54505501
if (g_dsl_tcc_api.tcc_add_library_fn) {
54515502
(void)g_dsl_tcc_api.tcc_add_library_fn(state, "m");
@@ -5563,6 +5614,59 @@ static bool dsl_jit_cc_math_bridge_available(void) {
55635614
#endif
55645615
}
55655616

5617+
static void dsl_jit_cc_add_library_flag_if_exists(char *flags, size_t flags_size, const char *path) {
5618+
if (!flags || flags_size == 0 || !path || path[0] == '\0') {
5619+
return;
5620+
}
5621+
struct stat st;
5622+
if (stat(path, &st) != 0 || !S_ISDIR(st.st_mode)) {
5623+
return;
5624+
}
5625+
size_t len = strlen(flags);
5626+
if (len >= flags_size - 1) {
5627+
return;
5628+
}
5629+
int n = snprintf(flags + len, flags_size - len, " -L%s", path);
5630+
if (n <= 0 || (size_t)n >= (flags_size - len)) {
5631+
flags[flags_size - 1] = '\0';
5632+
}
5633+
}
5634+
5635+
static void dsl_jit_cc_add_multiarch_library_flags(char *flags, size_t flags_size) {
5636+
if (!flags || flags_size == 0) {
5637+
return;
5638+
}
5639+
flags[0] = '\0';
5640+
#if defined(__linux__)
5641+
/* Match libtcc fallback dirs so cc JIT can resolve -lm on multiarch layouts. */
5642+
const char *paths[] = {
5643+
#if defined(__x86_64__) || defined(__amd64__)
5644+
"/usr/lib/x86_64-linux-gnu", "/lib/x86_64-linux-gnu",
5645+
#elif defined(__aarch64__)
5646+
"/usr/lib/aarch64-linux-gnu", "/lib/aarch64-linux-gnu",
5647+
#elif defined(__arm__)
5648+
"/usr/lib/arm-linux-gnueabihf", "/lib/arm-linux-gnueabihf",
5649+
"/usr/lib/arm-linux-gnueabi", "/lib/arm-linux-gnueabi",
5650+
#elif defined(__riscv) && (__riscv_xlen == 64)
5651+
"/usr/lib/riscv64-linux-gnu", "/lib/riscv64-linux-gnu",
5652+
#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)
5653+
"/usr/lib/powerpc64le-linux-gnu", "/lib/powerpc64le-linux-gnu",
5654+
#elif defined(__s390x__)
5655+
"/usr/lib/s390x-linux-gnu", "/lib/s390x-linux-gnu",
5656+
#elif defined(__i386__)
5657+
"/usr/lib/i386-linux-gnu", "/lib/i386-linux-gnu",
5658+
#endif
5659+
"/usr/lib64", "/lib64",
5660+
NULL
5661+
};
5662+
for (int i = 0; paths[i]; i++) {
5663+
dsl_jit_cc_add_library_flag_if_exists(flags, flags_size, paths[i]);
5664+
}
5665+
#else
5666+
(void)flags_size;
5667+
#endif
5668+
}
5669+
55665670
static bool dsl_jit_compile_shared(const me_dsl_compiled_program *program,
55675671
const char *src_path, const char *so_path) {
55685672
if (!program || !src_path || !so_path) {
@@ -5583,21 +5687,28 @@ static bool dsl_jit_compile_shared(const me_dsl_compiled_program *program,
55835687
const char *debug_cc = getenv("ME_DSL_JIT_DEBUG_CC");
55845688
bool show_cc_output = (debug_cc && debug_cc[0] != '\0' && strcmp(debug_cc, "0") != 0);
55855689
const char *bridge_ldflags = "";
5690+
char multiarch_ldflags[512];
5691+
const char *math_ldflags = "";
5692+
dsl_jit_cc_add_multiarch_library_flags(multiarch_ldflags, sizeof(multiarch_ldflags));
55865693
#if defined(__APPLE__)
55875694
if (program->jit_use_runtime_math_bridge) {
55885695
bridge_ldflags = " -Wl,-undefined,dynamic_lookup";
55895696
}
5697+
#elif !defined(_WIN32) && !defined(_WIN64)
5698+
math_ldflags = " -lm";
55905699
#endif
55915700
char cmd[2048];
55925701
#if defined(__APPLE__)
55935702
int n = snprintf(cmd, sizeof(cmd),
5594-
"%s -std=c99 -O3 -fPIC %s %s -dynamiclib -o \"%s\" \"%s\"%s%s",
5703+
"%s -std=c99 -O3 -fPIC %s %s -dynamiclib -o \"%s\" \"%s\"%s%s%s%s",
55955704
cc, fp_cflags, cflags, so_path, src_path, bridge_ldflags,
5705+
multiarch_ldflags, math_ldflags,
55965706
show_cc_output ? "" : " >/dev/null 2>&1");
55975707
#else
55985708
int n = snprintf(cmd, sizeof(cmd),
5599-
"%s -std=c99 -O3 -fPIC %s %s -shared -o \"%s\" \"%s\"%s%s",
5709+
"%s -std=c99 -O3 -fPIC %s %s -shared -o \"%s\" \"%s\"%s%s%s%s",
56005710
cc, fp_cflags, cflags, so_path, src_path, bridge_ldflags,
5711+
multiarch_ldflags, math_ldflags,
56015712
show_cc_output ? "" : " >/dev/null 2>&1");
56025713
#endif
56035714
if (n <= 0 || (size_t)n >= sizeof(cmd)) {

0 commit comments

Comments
 (0)