authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-30 17:10:54-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-03-30 17:10:54-04:00
logb01c50d6fae581050affdc438942b979ae54a8da
treee0e2dba4af0bdb76f070b4391a5e22f47b471373
parentf586acabdcc4adaeda7bc278463c20e4033e8cc9

find libc and zig std lib at runtime

this removes the following configure options: * ZIG_LIBC_LIB_DIR * ZIG_LIBC_STATIC_LIB_DIR * ZIG_LIBC_INCLUDE_DIR * ZIG_DYNAMIC_LINKER * ZIG_EACH_LIB_RPATH * zig's reliance on CMAKE_INSTALL_PREFIX these options are still available as command line options, however, the default will attempt to execute the system's C compiler to collect system defaults for these values. closes #870

9 files changed, 171 insertions(+), 57 deletions(-)

CMakeLists.txt-5
...@@ -30,11 +30,6 @@ if(GIT_EXE)...@@ -30,11 +30,6 @@ if(GIT_EXE)
30endif()30endif()
31message("Configuring zig version ${ZIG_VERSION}")31message("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")
38set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")33set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
3934
40string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")35string(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....@@ -138,14 +138,10 @@ libc. Create demo games using Zig.
138138
139##### POSIX139##### 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
145```141```
146mkdir build142mkdir build
147cd build143cd 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)
149make145make
150make install146make install
151./zig build --build-file ../build.zig test147./zig build --build-file ../build.zig test
...@@ -153,8 +149,6 @@ make install...@@ -153,8 +149,6 @@ make install
153149
154##### MacOS150##### MacOS
155151
156`ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused.
157
158```152```
159brew install cmake llvm@6153brew install cmake llvm@6
160brew outdated llvm@6 || brew upgrade llvm@6154brew outdated llvm@6 || brew upgrade llvm@6
src/analyze.cpp+108-8
...@@ -4285,24 +4285,117 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {...@@ -4285,24 +4285,117 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
4285 return g->win_sdk;4285 return g->win_sdk;
4286}4286}
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
4288void find_libc_include_path(CodeGen *g) {4376void 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
4291 if (g->zig_target.os == OsWindows) {4379 if (g->zig_target.os == OsWindows) {
4292 ZigWindowsSDK *sdk = get_windows_sdk(g);4380 ZigWindowsSDK *sdk = get_windows_sdk(g);
4293 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {4381 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
4294 zig_panic("Unable to determine libc include path.");4382 zig_panic("Unable to determine libc include path.");
4295 }4383 }
4384 } else if (g->zig_target.os == OsLinux) {
4385 g->libc_include_dir = get_linux_libc_include_path();
4386 } else if (g->zig_target.os == OsMacOSX) {
4387 g->libc_include_dir = buf_create_from_str("/usr/include");
4388 } else {
4389 // TODO find libc at runtime for other operating systems
4390 zig_panic("Unable to determine libc include path.");
4296 }4391 }
4297
4298 // TODO find libc at runtime for other operating systems
4299 zig_panic("Unable to determine libc include path.");
4300 }4392 }
4393 assert(buf_len(g->libc_include_dir) != 0);
4301}4394}
43024395
4303void find_libc_lib_path(CodeGen *g) {4396void find_libc_lib_path(CodeGen *g) {
4304 // later we can handle this better by reporting an error via the normal mechanism4397 // 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 ||4398 if (g->libc_lib_dir == nullptr ||
4306 (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))4399 (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))
4307 {4400 {
4308 if (g->zig_target.os == OsWindows) {4401 if (g->zig_target.os == OsWindows) {
...@@ -4326,18 +4419,25 @@ void find_libc_lib_path(CodeGen *g) {...@@ -4326,18 +4419,25 @@ void find_libc_lib_path(CodeGen *g) {
4326 g->msvc_lib_dir = vc_lib_dir;4419 g->msvc_lib_dir = vc_lib_dir;
4327 g->libc_lib_dir = ucrt_lib_path;4420 g->libc_lib_dir = ucrt_lib_path;
4328 g->kernel32_lib_dir = kern_lib_path;4421 g->kernel32_lib_dir = kern_lib_path;
4422 } else if (g->zig_target.os == OsLinux) {
4423 g->libc_lib_dir = get_linux_libc_lib_path("crt1.o");
4329 } else {4424 } else {
4330 zig_panic("Unable to determine libc lib path.");4425 zig_panic("Unable to determine libc lib path.");
4331 }4426 }
4427 } else {
4428 assert(buf_len(g->libc_lib_dir) != 0);
4332 }4429 }
43334430
4334 if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) {4431 if (g->libc_static_lib_dir == nullptr) {
4335 if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {4432 if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {
4336 return;4433 return;
4337 }4434 } else if (g->zig_target.os == OsLinux) {
4338 else {4435 g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o");
4436 } else {
4339 zig_panic("Unable to determine libc static lib path.");4437 zig_panic("Unable to determine libc static lib path.");
4340 }4438 }
4439 } else {
4440 assert(buf_len(g->libc_static_lib_dir) != 0);
4341 }4441 }
4342}4442}
43434443
src/codegen.cpp+8-11
...@@ -112,10 +112,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -112,10 +112,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
112 // that's for native compilation112 // that's for native compilation
113 g->zig_target = *target;113 g->zig_target = *target;
114 resolve_target_object_format(&g->zig_target);114 resolve_target_object_format(&g->zig_target);
115 g->dynamic_linker = buf_create_from_str("");115 g->dynamic_linker = nullptr;
116 g->libc_lib_dir = buf_create_from_str("");116 g->libc_lib_dir = nullptr;
117 g->libc_static_lib_dir = buf_create_from_str("");117 g->libc_static_lib_dir = nullptr;
118 g->libc_include_dir = buf_create_from_str("");118 g->libc_include_dir = nullptr;
119 g->msvc_lib_dir = nullptr;119 g->msvc_lib_dir = nullptr;
120 g->kernel32_lib_dir = nullptr;120 g->kernel32_lib_dir = nullptr;
121 g->each_lib_rpath = false;121 g->each_lib_rpath = false;
...@@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
123 // native compilation, we can rely on the configuration stuff123 // native compilation, we can rely on the configuration stuff
124 g->is_native_target = true;124 g->is_native_target = true;
125 get_native_target(&g->zig_target);125 get_native_target(&g->zig_target);
126 g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER);126 g->dynamic_linker = nullptr; // find it at runtime
127 g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR);127 g->libc_lib_dir = nullptr; // find it at runtime
128 g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR);128 g->libc_static_lib_dir = nullptr; // find it at runtime
129 g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR);129 g->libc_include_dir = nullptr; // find it at runtime
130 g->msvc_lib_dir = nullptr; // find it at runtime130 g->msvc_lib_dir = nullptr; // find it at runtime
131 g->kernel32_lib_dir = nullptr; // find it at runtime131 g->kernel32_lib_dir = nullptr; // find it at runtime
132
133#ifdef ZIG_EACH_LIB_RPATH
134 g->each_lib_rpath = true;132 g->each_lib_rpath = true;
135#endif
136133
137 if (g->zig_target.os == OsMacOSX ||134 if (g->zig_target.os == OsMacOSX ||
138 g->zig_target.os == OsIOS)135 g->zig_target.os == OsIOS)
src/config.h.in-8
...@@ -13,14 +13,6 @@...@@ -13,14 +13,6 @@
13#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@13#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@
14#define ZIG_VERSION_STRING "@ZIG_VERSION@"14#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
24// Only used for running tests before installing.16// Only used for running tests before installing.
25#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"17#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"
2618
src/link.cpp+38-6
...@@ -164,6 +164,34 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {...@@ -164,6 +164,34 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {
164 lj->rpath_table.put(rpath, true);164 lj->rpath_table.put(rpath, true);
165}165}
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
167static void construct_linker_job_elf(LinkJob *lj) {195static void construct_linker_job_elf(LinkJob *lj) {
168 CodeGen *g = lj->codegen;196 CodeGen *g = lj->codegen;
169197
...@@ -259,12 +287,16 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -259,12 +287,16 @@ static void construct_linker_job_elf(LinkJob *lj) {
259 lj->args.append(buf_ptr(g->libc_static_lib_dir));287 lj->args.append(buf_ptr(g->libc_static_lib_dir));
260 }288 }
261289
262 if (g->dynamic_linker && buf_len(g->dynamic_linker) > 0) {290 if (!g->is_static) {
263 lj->args.append("-dynamic-linker");291 if (g->dynamic_linker != nullptr) {
264 lj->args.append(buf_ptr(g->dynamic_linker));292 assert(buf_len(g->dynamic_linker) != 0);
265 } else {293 lj->args.append("-dynamic-linker");
266 lj->args.append("-dynamic-linker");294 lj->args.append(buf_ptr(g->dynamic_linker));
267 lj->args.append(buf_ptr(target_dynamic_linker(&g->zig_target)));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 }
268 }300 }
269301
270 if (shared) {302 if (shared) {
src/main.cpp-7
...@@ -195,13 +195,6 @@ static int find_zig_lib_dir(Buf *out_path) {...@@ -195,13 +195,6 @@ static int find_zig_lib_dir(Buf *out_path) {
195 }195 }
196 }196 }
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
205 return ErrorFileNotFound;198 return ErrorFileNotFound;
206}199}
207200
src/os.cpp+12-5
...@@ -57,10 +57,6 @@ static clock_serv_t cclock;...@@ -57,10 +57,6 @@ static clock_serv_t cclock;
57#include <errno.h>57#include <errno.h>
58#include <time.h>58#include <time.h>
5959
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
64#if defined(ZIG_OS_POSIX)60#if defined(ZIG_OS_POSIX)
65static void populate_termination(Termination *term, int status) {61static void populate_termination(Termination *term, int status) {
66 if (WIFEXITED(status)) {62 if (WIFEXITED(status)) {
...@@ -929,7 +925,18 @@ int os_self_exe_path(Buf *out_path) {...@@ -929,7 +925,18 @@ int os_self_exe_path(Buf *out_path) {
929#elif defined(ZIG_OS_DARWIN)925#elif defined(ZIG_OS_DARWIN)
930 return ErrorFileNotFound;926 return ErrorFileNotFound;
931#elif defined(ZIG_OS_LINUX)927#elif defined(ZIG_OS_LINUX)
932 return ErrorFileNotFound;928 buf_resize(out_path, 256);
929 for (;;) {
930 ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
931 if (amt == -1) {
932 return ErrorUnexpected;
933 }
934 if (amt == (ssize_t)buf_len(out_path)) {
935 buf_resize(out_path, buf_len(out_path) * 2);
936 continue;
937 }
938 return 0;
939 }
933#endif940#endif
934 return ErrorFileNotFound;941 return ErrorFileNotFound;
935}942}
src/target.cpp+4
...@@ -863,6 +863,10 @@ Buf *target_dynamic_linker(ZigTarget *target) {...@@ -863,6 +863,10 @@ Buf *target_dynamic_linker(ZigTarget *target) {
863 env == ZigLLVM_GNUX32)863 env == ZigLLVM_GNUX32)
864 {864 {
865 return buf_create_from_str("/libx32/ld-linux-x32.so.2");865 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");
866 } else {870 } else {
867 return buf_create_from_str("/lib64/ld-linux-x86-64.so.2");871 return buf_create_from_str("/lib64/ld-linux-x86-64.so.2");
868 }872 }