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)
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
src/analyze.cpp+108-8
......@@ -4285,24 +4285,117 @@ 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);
42934381 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
42944382 zig_panic("Unable to determine libc include path.");
42954383 }
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.");
42964391 }
4297
4298 // TODO find libc at runtime for other operating systems
4299 zig_panic("Unable to determine libc include path.");
43004392 }
4393 assert(buf_len(g->libc_include_dir) != 0);
43014394}
43024395
43034396void find_libc_lib_path(CodeGen *g) {
43044397 // 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 ||
43064399 (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))
43074400 {
43084401 if (g->zig_target.os == OsWindows) {
......@@ -4326,18 +4419,25 @@ void find_libc_lib_path(CodeGen *g) {
43264419 g->msvc_lib_dir = vc_lib_dir;
43274420 g->libc_lib_dir = ucrt_lib_path;
43284421 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");
43294424 } else {
43304425 zig_panic("Unable to determine libc lib path.");
43314426 }
4427 } else {
4428 assert(buf_len(g->libc_lib_dir) != 0);
43324429 }
43334430
4334 if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) {
4431 if (g->libc_static_lib_dir == nullptr) {
43354432 if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {
43364433 return;
4337 }
4338 else {
4434 } else if (g->zig_target.os == OsLinux) {
4435 g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o");
4436 } else {
43394437 zig_panic("Unable to determine libc static lib path.");
43404438 }
4439 } else {
4440 assert(buf_len(g->libc_static_lib_dir) != 0);
43414441 }
43424442}
43434443
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+38-6
......@@ -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) {
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+12-5
......@@ -57,10 +57,6 @@ static clock_serv_t cclock;
5757#include <errno.h>
5858#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
6460#if defined(ZIG_OS_POSIX)
6561static void populate_termination(Termination *term, int status) {
6662 if (WIFEXITED(status)) {
......@@ -929,7 +925,18 @@ int os_self_exe_path(Buf *out_path) {
929925#elif defined(ZIG_OS_DARWIN)
930926 return ErrorFileNotFound;
931927#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 }
933940#endif
934941 return ErrorFileNotFound;
935942}
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 }