authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-31 12:13:30-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-03-31 12:13:30-04:00
log51a6ff18d454f4cb0faa0f1837df9f0c55a80b43
treebd603e96266978590f4c2d6201829f8817a64f3c
parent7d66908f294eed1138802c060185721a2e265f3b
parent8f962a957a3645342fba8219cf8f33d0ac42e16d
signature Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #872 from zig-lang/runtime-libc

find libc and zig std lib at runtime

11 files changed, 185 insertions(+), 63 deletions(-)

CMakeLists.txt-5
......@@ -30,11 +30,6 @@ if(GIT_EXE)
3030endif()
3131message("Configuring zig version ${ZIG_VERSION}")
3232
33set(ZIG_LIBC_LIB_DIR "" CACHE STRING "Default native target libc directory where crt1.o can be found")
34set(ZIG_LIBC_STATIC_LIB_DIR "" CACHE STRING "Default native target libc directory where crtbeginT.o can be found")
35set(ZIG_LIBC_INCLUDE_DIR "/usr/include" CACHE STRING "Default native target libc include directory")
36set(ZIG_DYNAMIC_LINKER "" CACHE STRING "Override dynamic linker for native target")
37set(ZIG_EACH_LIB_RPATH off CACHE BOOL "Add each dynamic library to rpath for native target")
3833set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
3934
4035string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")
README.md+1-7
......@@ -138,14 +138,10 @@ libc. Create demo games using Zig.
138138
139139##### POSIX
140140
141If 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```
146142mkdir build
147143cd build
148cmake .. -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))
144cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
149145make
150146make install
151147./zig build --build-file ../build.zig test
......@@ -153,8 +149,6 @@ make install
153149
154150##### MacOS
155151
156`ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused.
157
158152```
159153brew install cmake llvm@6
160154brew outdated llvm@6 || brew upgrade llvm@6
ci/appveyor/build_script.bat+1-3
......@@ -20,9 +20,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_
2020
2121mkdir %ZIGBUILDDIR%
2222cd %ZIGBUILDDIR%
23cmake.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
23cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release || exit /b
2424msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b
2525
2626bin\zig.exe build --build-file ..\build.zig test || exit /b
27
28@echo "MSVC build succeeded"
ci/travis_linux_script+1-1
......@@ -8,7 +8,7 @@ export CXX=clang++-6.0
88echo $PATH
99mkdir build
1010cd build
11cmake .. -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))
11cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
1212make VERBOSE=1
1313make install
1414./zig build --build-file ../build.zig test
src/analyze.cpp+109-8
......@@ -4285,24 +4285,118 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
42854285 return g->win_sdk;
42864286}
42874287
4288
4289Buf *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
4315Buf *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
42884376void 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
43034397void 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+8-11
......@@ -112,10 +112,10 @@ 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;
......@@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
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-8
......@@ -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+41-7
......@@ -164,6 +164,34 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {
164164 lj->rpath_table.put(rpath, true);
165165}
166166
167static 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
167195static 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-7
......@@ -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+20-6
......@@ -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)
6562static 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}
src/target.cpp+4
......@@ -863,6 +863,10 @@ Buf *target_dynamic_linker(ZigTarget *target) {
863863 env == ZigLLVM_GNUX32)
864864 {
865865 return buf_create_from_str("/libx32/ld-linux-x32.so.2");
866 } else if (arch == ZigLLVM_x86_64 &&
867 (env == ZigLLVM_Musl || env == ZigLLVM_MuslEABI || env == ZigLLVM_MuslEABIHF))
868 {
869 return buf_create_from_str("/lib/ld-musl-x86_64.so.1");
866870 } else {
867871 return buf_create_from_str("/lib64/ld-linux-x86-64.so.2");
868872 }