Skip to content

Commit 51a6ff1

Browse files
authored
Merge pull request #872 from zig-lang/runtime-libc
find libc and zig std lib at runtime
2 parents 7d66908 + 8f962a9 commit 51a6ff1

11 files changed

+185
-63
lines changed

CMakeLists.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,6 @@ if(GIT_EXE)
3030
endif()
3131
message("Configuring zig version ${ZIG_VERSION}")
3232

33-
set(ZIG_LIBC_LIB_DIR "" CACHE STRING "Default native target libc directory where crt1.o can be found")
34-
set(ZIG_LIBC_STATIC_LIB_DIR "" CACHE STRING "Default native target libc directory where crtbeginT.o can be found")
35-
set(ZIG_LIBC_INCLUDE_DIR "/usr/include" CACHE STRING "Default native target libc include directory")
36-
set(ZIG_DYNAMIC_LINKER "" CACHE STRING "Override dynamic linker for native target")
37-
set(ZIG_EACH_LIB_RPATH off CACHE BOOL "Add each dynamic library to rpath for native target")
3833
set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
3934

4035
string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")

README.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -138,23 +138,17 @@ libc. Create demo games using Zig.
138138

139139
##### POSIX
140140

141-
If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`,
142-
`ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to
143-
(example below).
144-
145141
```
146142
mkdir build
147143
cd build
148-
cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | cc -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $(cc -print-file-name=crtbegin.o))
144+
cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
149145
make
150146
make install
151147
./zig build --build-file ../build.zig test
152148
```
153149

154150
##### MacOS
155151

156-
`ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused.
157-
158152
```
159153
brew install cmake llvm@6
160154
brew outdated llvm@6 || brew upgrade llvm@6

ci/appveyor/build_script.bat

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_
2020

2121
mkdir %ZIGBUILDDIR%
2222
cd %ZIGBUILDDIR%
23-
cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release "-DZIG_LIBC_INCLUDE_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt" "-DZIG_LIBC_LIB_DIR=C:\Program Files (x86)\Windows Kits\10\bin\x64\ucrt" "-DZIG_LIBC_STATIC_LIB_DIR=C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64" || exit /b
23+
cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release || exit /b
2424
msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b
2525

2626
bin\zig.exe build --build-file ..\build.zig test || exit /b
27-
28-
@echo "MSVC build succeeded"

ci/travis_linux_script

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ export CXX=clang++-6.0
88
echo $PATH
99
mkdir build
1010
cd build
11-
cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $($CC -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | $CC -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $($CC -print-file-name=crtbegin.o))
11+
cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
1212
make VERBOSE=1
1313
make install
1414
./zig build --build-file ../build.zig test

src/analyze.cpp

Lines changed: 109 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4285,24 +4285,118 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
42854285
return g->win_sdk;
42864286
}
42874287

4288+
4289+
Buf *get_linux_libc_lib_path(const char *o_file) {
4290+
const char *cc_exe = getenv("CC");
4291+
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
4292+
ZigList<const char *> args = {};
4293+
args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));
4294+
Termination term;
4295+
Buf *out_stderr = buf_alloc();
4296+
Buf *out_stdout = buf_alloc();
4297+
int err;
4298+
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
4299+
zig_panic("unable to determine libc lib path: executing C compiler: %s", err_str(err));
4300+
}
4301+
if (term.how != TerminationIdClean || term.code != 0) {
4302+
zig_panic("unable to determine libc lib path: executing C compiler command failed");
4303+
}
4304+
if (buf_ends_with_str(out_stdout, "\n")) {
4305+
buf_resize(out_stdout, buf_len(out_stdout) - 1);
4306+
}
4307+
if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) {
4308+
zig_panic("unable to determine libc lib path: C compiler could not find %s", o_file);
4309+
}
4310+
Buf *result = buf_alloc();
4311+
os_path_dirname(out_stdout, result);
4312+
return result;
4313+
}
4314+
4315+
Buf *get_linux_libc_include_path(void) {
4316+
const char *cc_exe = getenv("CC");
4317+
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
4318+
ZigList<const char *> args = {};
4319+
args.append("-E");
4320+
args.append("-Wp,-v");
4321+
args.append("-xc");
4322+
args.append("/dev/null");
4323+
Termination term;
4324+
Buf *out_stderr = buf_alloc();
4325+
Buf *out_stdout = buf_alloc();
4326+
int err;
4327+
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
4328+
zig_panic("unable to determine libc include path: executing C compiler: %s", err_str(err));
4329+
}
4330+
if (term.how != TerminationIdClean || term.code != 0) {
4331+
zig_panic("unable to determine libc include path: executing C compiler command failed");
4332+
}
4333+
char *prev_newline = buf_ptr(out_stderr);
4334+
ZigList<const char *> search_paths = {};
4335+
bool found_search_paths = false;
4336+
for (;;) {
4337+
char *newline = strchr(prev_newline, '\n');
4338+
if (newline == nullptr) {
4339+
zig_panic("unable to determine libc include path: bad output from C compiler command");
4340+
}
4341+
*newline = 0;
4342+
if (found_search_paths) {
4343+
if (strcmp(prev_newline, "End of search list.") == 0) {
4344+
break;
4345+
}
4346+
search_paths.append(prev_newline);
4347+
} else {
4348+
if (strcmp(prev_newline, "#include <...> search starts here:") == 0) {
4349+
found_search_paths = true;
4350+
}
4351+
}
4352+
prev_newline = newline + 1;
4353+
}
4354+
if (search_paths.length == 0) {
4355+
zig_panic("unable to determine libc include path: even C compiler does not know where libc headers are");
4356+
}
4357+
for (size_t i = 0; i < search_paths.length; i += 1) {
4358+
// search in reverse order
4359+
const char *search_path = search_paths.items[search_paths.length - i - 1];
4360+
// cut off spaces
4361+
while (*search_path == ' ') {
4362+
search_path += 1;
4363+
}
4364+
Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path);
4365+
bool exists;
4366+
if ((err = os_file_exists(stdlib_path, &exists))) {
4367+
exists = false;
4368+
}
4369+
if (exists) {
4370+
return buf_create_from_str(search_path);
4371+
}
4372+
}
4373+
zig_panic("unable to determine libc include path: stdlib.h not found in C compiler search paths");
4374+
}
4375+
42884376
void find_libc_include_path(CodeGen *g) {
4289-
if (!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) {
4377+
if (g->libc_include_dir == nullptr) {
42904378

42914379
if (g->zig_target.os == OsWindows) {
42924380
ZigWindowsSDK *sdk = get_windows_sdk(g);
4381+
g->libc_include_dir = buf_alloc();
42934382
if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
42944383
zig_panic("Unable to determine libc include path.");
42954384
}
4385+
} else if (g->zig_target.os == OsLinux) {
4386+
g->libc_include_dir = get_linux_libc_include_path();
4387+
} else if (g->zig_target.os == OsMacOSX) {
4388+
g->libc_include_dir = buf_create_from_str("/usr/include");
4389+
} else {
4390+
// TODO find libc at runtime for other operating systems
4391+
zig_panic("Unable to determine libc include path.");
42964392
}
4297-
4298-
// TODO find libc at runtime for other operating systems
4299-
zig_panic("Unable to determine libc include path.");
43004393
}
4394+
assert(buf_len(g->libc_include_dir) != 0);
43014395
}
43024396

43034397
void find_libc_lib_path(CodeGen *g) {
43044398
// later we can handle this better by reporting an error via the normal mechanism
4305-
if (!g->libc_lib_dir || buf_len(g->libc_lib_dir) == 0 ||
4399+
if (g->libc_lib_dir == nullptr ||
43064400
(g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))
43074401
{
43084402
if (g->zig_target.os == OsWindows) {
@@ -4326,18 +4420,25 @@ void find_libc_lib_path(CodeGen *g) {
43264420
g->msvc_lib_dir = vc_lib_dir;
43274421
g->libc_lib_dir = ucrt_lib_path;
43284422
g->kernel32_lib_dir = kern_lib_path;
4423+
} else if (g->zig_target.os == OsLinux) {
4424+
g->libc_lib_dir = get_linux_libc_lib_path("crt1.o");
43294425
} else {
43304426
zig_panic("Unable to determine libc lib path.");
43314427
}
4428+
} else {
4429+
assert(buf_len(g->libc_lib_dir) != 0);
43324430
}
43334431

4334-
if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) {
4432+
if (g->libc_static_lib_dir == nullptr) {
43354433
if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {
43364434
return;
4337-
}
4338-
else {
4435+
} else if (g->zig_target.os == OsLinux) {
4436+
g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o");
4437+
} else {
43394438
zig_panic("Unable to determine libc static lib path.");
43404439
}
4440+
} else {
4441+
assert(buf_len(g->libc_static_lib_dir) != 0);
43414442
}
43424443
}
43434444

src/codegen.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -112,27 +112,24 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
112112
// that's for native compilation
113113
g->zig_target = *target;
114114
resolve_target_object_format(&g->zig_target);
115-
g->dynamic_linker = buf_create_from_str("");
116-
g->libc_lib_dir = buf_create_from_str("");
117-
g->libc_static_lib_dir = buf_create_from_str("");
118-
g->libc_include_dir = buf_create_from_str("");
115+
g->dynamic_linker = nullptr;
116+
g->libc_lib_dir = nullptr;
117+
g->libc_static_lib_dir = nullptr;
118+
g->libc_include_dir = nullptr;
119119
g->msvc_lib_dir = nullptr;
120120
g->kernel32_lib_dir = nullptr;
121121
g->each_lib_rpath = false;
122122
} else {
123123
// native compilation, we can rely on the configuration stuff
124124
g->is_native_target = true;
125125
get_native_target(&g->zig_target);
126-
g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER);
127-
g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR);
128-
g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR);
129-
g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR);
126+
g->dynamic_linker = nullptr; // find it at runtime
127+
g->libc_lib_dir = nullptr; // find it at runtime
128+
g->libc_static_lib_dir = nullptr; // find it at runtime
129+
g->libc_include_dir = nullptr; // find it at runtime
130130
g->msvc_lib_dir = nullptr; // find it at runtime
131131
g->kernel32_lib_dir = nullptr; // find it at runtime
132-
133-
#ifdef ZIG_EACH_LIB_RPATH
134132
g->each_lib_rpath = true;
135-
#endif
136133

137134
if (g->zig_target.os == OsMacOSX ||
138135
g->zig_target.os == OsIOS)

src/config.h.in

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -13,14 +13,6 @@
1313
#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@
1414
#define ZIG_VERSION_STRING "@ZIG_VERSION@"
1515

16-
#define ZIG_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
17-
#define ZIG_LIBC_INCLUDE_DIR "@ZIG_LIBC_INCLUDE_DIR_ESCAPED@"
18-
#define ZIG_LIBC_LIB_DIR "@ZIG_LIBC_LIB_DIR_ESCAPED@"
19-
#define ZIG_LIBC_STATIC_LIB_DIR "@ZIG_LIBC_STATIC_LIB_DIR_ESCAPED@"
20-
#define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@"
21-
22-
#cmakedefine ZIG_EACH_LIB_RPATH
23-
2416
// Only used for running tests before installing.
2517
#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"
2618

src/link.cpp

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,34 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {
164164
lj->rpath_table.put(rpath, true);
165165
}
166166

167+
static Buf *get_dynamic_linker_path(CodeGen *g) {
168+
if (g->is_native_target && g->zig_target.arch.arch == ZigLLVM_x86_64) {
169+
const char *cc_exe = getenv("CC");
170+
cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
171+
ZigList<const char *> args = {};
172+
args.append("-print-file-name=ld-linux-x86-64.so.2");
173+
Termination term;
174+
Buf *out_stderr = buf_alloc();
175+
Buf *out_stdout = buf_alloc();
176+
int err;
177+
if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
178+
return target_dynamic_linker(&g->zig_target);
179+
}
180+
if (term.how != TerminationIdClean || term.code != 0) {
181+
return target_dynamic_linker(&g->zig_target);
182+
}
183+
if (buf_ends_with_str(out_stdout, "\n")) {
184+
buf_resize(out_stdout, buf_len(out_stdout) - 1);
185+
}
186+
if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, "ld-linux-x86-64.so.2")) {
187+
return target_dynamic_linker(&g->zig_target);
188+
}
189+
return out_stdout;
190+
} else {
191+
return target_dynamic_linker(&g->zig_target);
192+
}
193+
}
194+
167195
static void construct_linker_job_elf(LinkJob *lj) {
168196
CodeGen *g = lj->codegen;
169197

@@ -259,12 +287,16 @@ static void construct_linker_job_elf(LinkJob *lj) {
259287
lj->args.append(buf_ptr(g->libc_static_lib_dir));
260288
}
261289

262-
if (g->dynamic_linker && buf_len(g->dynamic_linker) > 0) {
263-
lj->args.append("-dynamic-linker");
264-
lj->args.append(buf_ptr(g->dynamic_linker));
265-
} else {
266-
lj->args.append("-dynamic-linker");
267-
lj->args.append(buf_ptr(target_dynamic_linker(&g->zig_target)));
290+
if (!g->is_static) {
291+
if (g->dynamic_linker != nullptr) {
292+
assert(buf_len(g->dynamic_linker) != 0);
293+
lj->args.append("-dynamic-linker");
294+
lj->args.append(buf_ptr(g->dynamic_linker));
295+
} else {
296+
Buf *resolved_dynamic_linker = get_dynamic_linker_path(g);
297+
lj->args.append("-dynamic-linker");
298+
lj->args.append(buf_ptr(resolved_dynamic_linker));
299+
}
268300
}
269301

270302
if (shared) {
@@ -423,7 +455,9 @@ static void construct_linker_job_coff(LinkJob *lj) {
423455
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
424456

425457
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
426-
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
458+
if (g->libc_static_lib_dir != nullptr) {
459+
lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
460+
}
427461
}
428462

429463
if (lj->link_in_crt) {

src/main.cpp

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -195,13 +195,6 @@ static int find_zig_lib_dir(Buf *out_path) {
195195
}
196196
}
197197

198-
if (ZIG_INSTALL_PREFIX != nullptr) {
199-
if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) {
200-
return 0;
201-
}
202-
}
203-
204-
205198
return ErrorFileNotFound;
206199
}
207200

src/os.cpp

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ typedef SSIZE_T ssize_t;
4545
#if defined(__MACH__)
4646
#include <mach/clock.h>
4747
#include <mach/mach.h>
48+
#include <mach-o/dyld.h>
4849
#endif
4950

5051
#if defined(ZIG_OS_WINDOWS)
@@ -57,10 +58,6 @@ static clock_serv_t cclock;
5758
#include <errno.h>
5859
#include <time.h>
5960

60-
// these implementations are lazy. But who cares, we'll make a robust
61-
// implementation in the zig standard library and then this code all gets
62-
// deleted when we self-host. it works for now.
63-
6461
#if defined(ZIG_OS_POSIX)
6562
static void populate_termination(Termination *term, int status) {
6663
if (WIFEXITED(status)) {
@@ -927,9 +924,26 @@ int os_self_exe_path(Buf *out_path) {
927924
}
928925

929926
#elif defined(ZIG_OS_DARWIN)
930-
return ErrorFileNotFound;
927+
uint32_t u32_len = 0;
928+
int ret1 = _NSGetExecutablePath(nullptr, &u32_len);
929+
assert(ret1 != 0);
930+
buf_resize(out_path, u32_len);
931+
int ret2 = _NSGetExecutablePath(buf_ptr(out_path), &u32_len);
932+
assert(ret2 == 0);
933+
return 0;
931934
#elif defined(ZIG_OS_LINUX)
932-
return ErrorFileNotFound;
935+
buf_resize(out_path, 256);
936+
for (;;) {
937+
ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
938+
if (amt == -1) {
939+
return ErrorUnexpected;
940+
}
941+
if (amt == (ssize_t)buf_len(out_path)) {
942+
buf_resize(out_path, buf_len(out_path) * 2);
943+
continue;
944+
}
945+
return 0;
946+
}
933947
#endif
934948
return ErrorFileNotFound;
935949
}

0 commit comments

Comments
 (0)