authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-07 17:23:17-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-12-07 17:27:09-07:00
log88dc688bbf10fb95c51783eca0526054d33ef5a1
tree5d1cf8d680faa08a722037b9ece2fdd0110c06d3
parent211ac00f8380629653ae475d7c347b0a67b480af

restore the option to build with cmake

restore cmake to be capable of figuring out the zig version restore config.h and config.zig. config.h is used to detect whether we should propagate cmake configuration information to build.zig; however it can be overridden with -Dstatic-llvm. fix not passing -DZIG_LINK_MODE with zig build. when using the cmake build path, build.zig no longer tries to call llvm-config. Instead it relies 100% on the LLVM_LIBRARIES cmake variable. build.zig logic reworked and simplified.

6 files changed, 324 insertions(+), 37 deletions(-)

CMakeLists.txt+42-2
......@@ -24,6 +24,34 @@ set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX
2424project(zig C CXX)
2525set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
2626
27set(ZIG_VERSION_MAJOR 0)
28set(ZIG_VERSION_MINOR 7)
29set(ZIG_VERSION_PATCH 0)
30set(ZIG_VERSION "" CACHE STRING "Override Zig version string. Default is to find out with git.")
31
32if("${ZIG_VERSION}" STREQUAL "")
33 set(ZIG_VERSION "${ZIG_VERSION_MAJOR}.${ZIG_VERSION_MINOR}.${ZIG_VERSION_PATCH}")
34 find_program(GIT_EXE NAMES git)
35 if(GIT_EXE)
36 execute_process(
37 COMMAND ${GIT_EXE} -C ${CMAKE_SOURCE_DIR} name-rev HEAD --tags --name-only --no-undefined --always
38 RESULT_VARIABLE EXIT_STATUS
39 OUTPUT_VARIABLE ZIG_GIT_REV
40 OUTPUT_STRIP_TRAILING_WHITESPACE
41 ERROR_QUIET)
42 if(EXIT_STATUS EQUAL "0")
43 if(ZIG_GIT_REV MATCHES "\\^0$")
44 if(NOT("${ZIG_GIT_REV}" STREQUAL "${ZIG_VERSION}^0"))
45 message("WARNING: Tag does not match configured Zig version")
46 endif()
47 else()
48 set(ZIG_VERSION "${ZIG_VERSION}+${ZIG_GIT_REV}")
49 endif()
50 endif()
51 endif()
52endif()
53message("Configuring zig version ${ZIG_VERSION}")
54
2755set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
2856set(ZIG_STATIC_LLVM off CACHE BOOL "Prefer linking against static LLVM libraries")
2957set(ZIG_PREFER_CLANG_CPP_DYLIB off CACHE BOOL "Try to link against -lclang-cpp")
......@@ -233,6 +261,8 @@ set(LIBC_FILES_DEST "${ZIG_LIB_DIR}/libc")
233261set(LIBUNWIND_FILES_DEST "${ZIG_LIB_DIR}/libunwind")
234262set(LIBCXX_FILES_DEST "${ZIG_LIB_DIR}/libcxx")
235263set(ZIG_STD_DEST "${ZIG_LIB_DIR}/std")
264set(ZIG_CONFIG_H_OUT "${CMAKE_BINARY_DIR}/config.h")
265set(ZIG_CONFIG_ZIG_OUT "${CMAKE_BINARY_DIR}/config.zig")
236266
237267# This is our shim which will be replaced by stage1.zig.
238268set(ZIG0_SOURCES
......@@ -280,6 +310,7 @@ set(ZIG_CPP_SOURCES
280310# then manually running the build-obj command (see BUILD_ZIG1_ARGS), and then looking
281311# in the zig-cache directory for the compiler-generated list of zig file dependencies.
282312set(ZIG_STAGE2_SOURCES
313 "${ZIG_CONFIG_ZIG_OUT}"
283314 "${CMAKE_SOURCE_DIR}/lib/std/array_hash_map.zig"
284315 "${CMAKE_SOURCE_DIR}/lib/std/array_list.zig"
285316 "${CMAKE_SOURCE_DIR}/lib/std/ascii.zig"
......@@ -519,7 +550,6 @@ set(ZIG_STAGE2_SOURCES
519550 "${CMAKE_SOURCE_DIR}/src/print_env.zig"
520551 "${CMAKE_SOURCE_DIR}/src/print_targets.zig"
521552 "${CMAKE_SOURCE_DIR}/src/stage1.zig"
522 "${CMAKE_SOURCE_DIR}/src/stage1_config.zig"
523553 "${CMAKE_SOURCE_DIR}/src/target.zig"
524554 "${CMAKE_SOURCE_DIR}/src/tracy.zig"
525555 "${CMAKE_SOURCE_DIR}/src/translate_c.zig"
......@@ -538,6 +568,15 @@ if(MSVC)
538568 endif()
539569endif()
540570
571configure_file (
572 "${CMAKE_SOURCE_DIR}/src/stage1/config.h.in"
573 "${ZIG_CONFIG_H_OUT}"
574)
575configure_file (
576 "${CMAKE_SOURCE_DIR}/src/config.zig.in"
577 "${ZIG_CONFIG_ZIG_OUT}"
578)
579
541580include_directories(
542581 ${CMAKE_SOURCE_DIR}
543582 ${CMAKE_BINARY_DIR}
......@@ -684,7 +723,7 @@ set(BUILD_ZIG1_ARGS
684723 "-femit-bin=${ZIG1_OBJECT}"
685724 "${ZIG1_RELEASE_ARG}"
686725 -lc
687 --pkg-begin build_options "${CMAKE_SOURCE_DIR}/src/stage1_config.zig"
726 --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}"
688727 --pkg-end
689728 --pkg-begin compiler_rt "${CMAKE_SOURCE_DIR}/lib/std/special/compiler_rt.zig"
690729 --pkg-end
......@@ -733,6 +772,7 @@ set(ZIG_INSTALL_ARGS "build"
733772 --override-lib-dir "${CMAKE_SOURCE_DIR}/lib"
734773 "-Dlib-files-only"
735774 --prefix "${CMAKE_INSTALL_PREFIX}"
775 "-Dconfig_h=${ZIG_CONFIG_H_OUT}"
736776 install
737777)
738778
build.zig+235-20
......@@ -54,7 +54,8 @@ pub fn build(b: *Builder) !void {
5454
5555 const only_install_lib_files = b.option(bool, "lib-files-only", "Only install library files") orelse false;
5656 const is_stage1 = b.option(bool, "stage1", "Build the stage1 compiler, put stage2 behind a feature flag") orelse false;
57 const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse is_stage1;
57 const static_llvm = b.option(bool, "static-llvm", "Disable integration with system-installed LLVM, Clang, LLD, and libc++") orelse false;
58 const enable_llvm = b.option(bool, "enable-llvm", "Build self-hosted compiler with LLVM backend enabled") orelse (is_stage1 or static_llvm);
5859 const config_h_path_option = b.option([]const u8, "config_h", "Path to the generated config.h");
5960
6061 b.installDirectory(InstallDirectoryOptions{
......@@ -89,6 +90,7 @@ pub fn build(b: *Builder) !void {
8990 exe.addBuildOption(bool, "skip_non_native", skip_non_native);
9091 exe.addBuildOption(bool, "have_llvm", enable_llvm);
9192 if (enable_llvm) {
93 const cmake_cfg = if (static_llvm) null else findAndParseConfigH(b, config_h_path_option);
9294 if (is_stage1) {
9395 exe.addIncludeDir("src");
9496 exe.addIncludeDir("deps/SoftFloat-3e/source/include");
......@@ -96,6 +98,7 @@ pub fn build(b: *Builder) !void {
9698 // of being built by cmake. But when built by zig it's gonna get a compiler_rt so that
9799 // is pointless.
98100 exe.addPackagePath("compiler_rt", "src/empty.zig");
101 exe.defineCMacro("ZIG_LINK_MODE=Static");
99102
100103 const softfloat = b.addStaticLibrary("softfloat", null);
101104 softfloat.setBuildMode(.ReleaseFast);
......@@ -121,31 +124,91 @@ pub fn build(b: *Builder) !void {
121124 };
122125 exe.addCSourceFiles(&stage1_sources, &exe_cflags);
123126 exe.addCSourceFiles(&optimized_c_sources, &[_][]const u8{ "-std=c99", "-O3" });
124 // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
125 // in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is
126 // unavailable when LLVM is compiled in Release mode.
127 const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"};
128 exe.addCSourceFiles(&zig_cpp_sources, &zig_cpp_cflags);
127 if (cmake_cfg == null) {
128 // We need this because otherwise zig_clang_cc1_main.cpp ends up pulling
129 // in a dependency on llvm::cfg::Update<llvm::BasicBlock*>::dump() which is
130 // unavailable when LLVM is compiled in Release mode.
131 const zig_cpp_cflags = exe_cflags ++ [_][]const u8{"-DNDEBUG=1"};
132 exe.addCSourceFiles(&zig_cpp_sources, &zig_cpp_cflags);
133 }
129134 }
135 if (cmake_cfg) |cfg| {
136 // Inside this code path, we have to coordinate with system packaged LLVM, Clang, and LLD.
137 // That means we also have to rely on stage1 compiled c++ files. We parse config.h to find
138 // the information passed on to us from cmake.
139 if (cfg.cmake_prefix_path.len > 0) {
140 b.addSearchPrefix(cfg.cmake_prefix_path);
141 }
142 exe.addObjectFile(fs.path.join(b.allocator, &[_][]const u8{
143 cfg.cmake_binary_dir,
144 "zigcpp",
145 b.fmt("{s}{s}{s}", .{ exe.target.libPrefix(), "zigcpp", exe.target.staticLibSuffix() }),
146 }) catch unreachable);
147 assert(cfg.lld_include_dir.len != 0);
148 exe.addIncludeDir(cfg.lld_include_dir);
149 addCMakeLibraryList(exe, cfg.clang_libraries);
150 addCMakeLibraryList(exe, cfg.lld_libraries);
151 addCMakeLibraryList(exe, cfg.llvm_libraries);
152
153 const need_cpp_includes = tracy != null;
154
155 // System -lc++ must be used because in this code path we are attempting to link
156 // against system-provided LLVM, Clang, LLD.
157 if (exe.target.getOsTag() == .linux) {
158 // First we try to static link against gcc libstdc++. If that doesn't work,
159 // we fall back to -lc++ and cross our fingers.
160 addCxxKnownPath(b, cfg, exe, "libstdc++.a", "", need_cpp_includes) catch |err| switch (err) {
161 error.RequiredLibraryNotFound => {
162 exe.linkSystemLibrary("c++");
163 },
164 else => |e| return e,
165 };
166
167 exe.linkSystemLibrary("pthread");
168 } else if (exe.target.isFreeBSD()) {
169 try addCxxKnownPath(b, cfg, exe, "libc++.a", null, need_cpp_includes);
170 exe.linkSystemLibrary("pthread");
171 } else if (exe.target.isDarwin()) {
172 if (addCxxKnownPath(b, cfg, exe, "libgcc_eh.a", "", need_cpp_includes)) {
173 // Compiler is GCC.
174 try addCxxKnownPath(b, cfg, exe, "libstdc++.a", null, need_cpp_includes);
175 exe.linkSystemLibrary("pthread");
176 // TODO LLD cannot perform this link.
177 // Set ZIG_SYSTEM_LINKER_HACK env var to use system linker ld instead.
178 // See https://github.com/ziglang/zig/issues/1535
179 } else |err| switch (err) {
180 error.RequiredLibraryNotFound => {
181 // System compiler, not gcc.
182 exe.linkSystemLibrary("c++");
183 },
184 else => |e| return e,
185 }
186 }
130187
131 for (clang_libs) |lib_name| {
132 exe.linkSystemLibrary(lib_name);
133 }
188 if (cfg.dia_guids_lib.len != 0) {
189 exe.addObjectFile(cfg.dia_guids_lib);
190 }
191 } else {
192 // Here we are -Denable-llvm but no cmake integration.
193 for (clang_libs) |lib_name| {
194 exe.linkSystemLibrary(lib_name);
195 }
134196
135 for (lld_libs) |lib_name| {
136 exe.linkSystemLibrary(lib_name);
137 }
197 for (lld_libs) |lib_name| {
198 exe.linkSystemLibrary(lib_name);
199 }
138200
139 for (llvm_libs) |lib_name| {
140 exe.linkSystemLibrary(lib_name);
141 }
201 for (llvm_libs) |lib_name| {
202 exe.linkSystemLibrary(lib_name);
203 }
142204
143 // This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
144 exe.linkSystemLibrary("c++");
205 // This means we rely on clang-or-zig-built LLVM, Clang, LLD libraries.
206 exe.linkSystemLibrary("c++");
145207
146 if (target.getOs().tag == .windows) {
147 exe.linkSystemLibrary("version");
148 exe.linkSystemLibrary("uuid");
208 if (target.getOs().tag == .windows) {
209 exe.linkSystemLibrary("version");
210 exe.linkSystemLibrary("uuid");
211 }
149212 }
150213 }
151214 if (link_libc) {
......@@ -281,6 +344,158 @@ pub fn build(b: *Builder) !void {
281344 test_step.dependOn(docs_step);
282345}
283346
347fn addCxxKnownPath(
348 b: *Builder,
349 ctx: CMakeConfig,
350 exe: *std.build.LibExeObjStep,
351 objname: []const u8,
352 errtxt: ?[]const u8,
353 need_cpp_includes: bool,
354) !void {
355 const path_padded = try b.exec(&[_][]const u8{
356 ctx.cxx_compiler,
357 b.fmt("-print-file-name={}", .{objname}),
358 });
359 const path_unpadded = mem.tokenize(path_padded, "\r\n").next().?;
360 if (mem.eql(u8, path_unpadded, objname)) {
361 if (errtxt) |msg| {
362 warn("{}", .{msg});
363 } else {
364 warn("Unable to determine path to {}\n", .{objname});
365 }
366 return error.RequiredLibraryNotFound;
367 }
368 exe.addObjectFile(path_unpadded);
369
370 // TODO a way to integrate with system c++ include files here
371 // cc -E -Wp,-v -xc++ /dev/null
372 if (need_cpp_includes) {
373 // I used these temporarily for testing something but we obviously need a
374 // more general purpose solution here.
375 //exe.addIncludeDir("/nix/store/b3zsk4ihlpiimv3vff86bb5bxghgdzb9-gcc-9.2.0/lib/gcc/x86_64-unknown-linux-gnu/9.2.0/../../../../include/c++/9.2.0");
376 //exe.addIncludeDir("/nix/store/b3zsk4ihlpiimv3vff86bb5bxghgdzb9-gcc-9.2.0/lib/gcc/x86_64-unknown-linux-gnu/9.2.0/../../../../include/c++/9.2.0/x86_64-unknown-linux-gnu");
377 //exe.addIncludeDir("/nix/store/b3zsk4ihlpiimv3vff86bb5bxghgdzb9-gcc-9.2.0/lib/gcc/x86_64-unknown-linux-gnu/9.2.0/../../../../include/c++/9.2.0/backward");
378 }
379}
380
381fn addCMakeLibraryList(exe: *std.build.LibExeObjStep, list: []const u8) void {
382 var it = mem.tokenize(list, ";");
383 while (it.next()) |lib| {
384 if (mem.startsWith(u8, lib, "-l")) {
385 exe.linkSystemLibrary(lib["-l".len..]);
386 } else {
387 exe.addObjectFile(lib);
388 }
389 }
390}
391
392const CMakeConfig = struct {
393 cmake_binary_dir: []const u8,
394 cmake_prefix_path: []const u8,
395 cxx_compiler: []const u8,
396 lld_include_dir: []const u8,
397 lld_libraries: []const u8,
398 clang_libraries: []const u8,
399 llvm_libraries: []const u8,
400 dia_guids_lib: []const u8,
401};
402
403const max_config_h_bytes = 1 * 1024 * 1024;
404
405fn findAndParseConfigH(b: *Builder, config_h_path_option: ?[]const u8) ?CMakeConfig {
406 const config_h_text: []const u8 = if (config_h_path_option) |config_h_path| blk: {
407 break :blk fs.cwd().readFileAlloc(b.allocator, config_h_path, max_config_h_bytes) catch unreachable;
408 } else blk: {
409 // TODO this should stop looking for config.h once it detects we hit the
410 // zig source root directory.
411 var check_dir = fs.path.dirname(b.zig_exe).?;
412 while (true) {
413 var dir = fs.cwd().openDir(check_dir, .{}) catch unreachable;
414 defer dir.close();
415
416 break :blk dir.readFileAlloc(b.allocator, "config.h", max_config_h_bytes) catch |err| switch (err) {
417 error.FileNotFound => {
418 const new_check_dir = fs.path.dirname(check_dir);
419 if (new_check_dir == null or mem.eql(u8, new_check_dir.?, check_dir)) {
420 return null;
421 }
422 check_dir = new_check_dir.?;
423 continue;
424 },
425 else => unreachable,
426 };
427 } else unreachable; // TODO should not need `else unreachable`.
428 };
429
430 var ctx: CMakeConfig = .{
431 .cmake_binary_dir = undefined,
432 .cmake_prefix_path = undefined,
433 .cxx_compiler = undefined,
434 .lld_include_dir = undefined,
435 .lld_libraries = undefined,
436 .clang_libraries = undefined,
437 .llvm_libraries = undefined,
438 .dia_guids_lib = undefined,
439 };
440
441 const mappings = [_]struct { prefix: []const u8, field: []const u8 }{
442 .{
443 .prefix = "#define ZIG_CMAKE_BINARY_DIR ",
444 .field = "cmake_binary_dir",
445 },
446 .{
447 .prefix = "#define ZIG_CMAKE_PREFIX_PATH ",
448 .field = "cmake_prefix_path",
449 },
450 .{
451 .prefix = "#define ZIG_CXX_COMPILER ",
452 .field = "cxx_compiler",
453 },
454 .{
455 .prefix = "#define ZIG_LLD_INCLUDE_PATH ",
456 .field = "lld_include_dir",
457 },
458 .{
459 .prefix = "#define ZIG_LLD_LIBRARIES ",
460 .field = "lld_libraries",
461 },
462 .{
463 .prefix = "#define ZIG_CLANG_LIBRARIES ",
464 .field = "clang_libraries",
465 },
466 .{
467 .prefix = "#define ZIG_LLVM_LIBRARIES ",
468 .field = "llvm_libraries",
469 },
470 .{
471 .prefix = "#define ZIG_DIA_GUIDS_LIB ",
472 .field = "dia_guids_lib",
473 },
474 };
475
476 var lines_it = mem.tokenize(config_h_text, "\r\n");
477 while (lines_it.next()) |line| {
478 inline for (mappings) |mapping| {
479 if (mem.startsWith(u8, line, mapping.prefix)) {
480 var it = mem.split(line, "\"");
481 _ = it.next().?; // skip the stuff before the quote
482 const quoted = it.next().?; // the stuff inside the quote
483 @field(ctx, mapping.field) = toNativePathSep(b, quoted);
484 }
485 }
486 }
487 return ctx;
488}
489
490fn toNativePathSep(b: *Builder, s: []const u8) []u8 {
491 const duplicated = mem.dupe(b.allocator, u8, s) catch unreachable;
492 for (duplicated) |*byte| switch (byte.*) {
493 '/' => byte.* = fs.path.sep,
494 else => {},
495 };
496 return duplicated;
497}
498
284499const softfloat_sources = [_][]const u8{
285500 "deps/SoftFloat-3e/source/8086/f128M_isSignalingNaN.c",
286501 "deps/SoftFloat-3e/source/8086/s_commonNaNToF128M.c",
src/config.zig.in created+13
......@@ -0,0 +1,13 @@
1pub const have_llvm = true;
2pub const version: [:0]const u8 = "@ZIG_VERSION@";
3pub const semver: @import("std").SemanticVersion = .{
4 .major = @ZIG_VERSION_MAJOR@,
5 .minor = @ZIG_VERSION_MINOR@,
6 .patch = @ZIG_VERSION_PATCH@,
7 .build = "@ZIG_GIT_REV@",
8};
9pub const log_scopes: []const []const u8 = &[_][]const u8{};
10pub const zir_dumps: []const []const u8 = &[_][]const u8{};
11pub const enable_tracy = false;
12pub const is_stage1 = true;
13pub const skip_non_native = false;
src/stage1/config.h.in created+27
......@@ -0,0 +1,27 @@
1/*
2 * Copyright (c) 2016 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_CONFIG_H
9#define ZIG_CONFIG_H
10
11// Used by zig0.cpp
12#define ZIG_VERSION_MAJOR @ZIG_VERSION_MAJOR@
13#define ZIG_VERSION_MINOR @ZIG_VERSION_MINOR@
14#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@
15#define ZIG_VERSION_STRING "@ZIG_VERSION@"
16
17// Used by build.zig for communicating build information to self hosted build.
18#define ZIG_CMAKE_BINARY_DIR "@CMAKE_BINARY_DIR@"
19#define ZIG_CMAKE_PREFIX_PATH "@CMAKE_PREFIX_PATH@"
20#define ZIG_CXX_COMPILER "@CMAKE_CXX_COMPILER@"
21#define ZIG_LLD_INCLUDE_PATH "@LLD_INCLUDE_DIRS@"
22#define ZIG_LLD_LIBRARIES "@LLD_LIBRARIES@"
23#define ZIG_CLANG_LIBRARIES "@CLANG_LIBRARIES@"
24#define ZIG_LLVM_LIBRARIES "@LLVM_LIBRARIES@"
25#define ZIG_DIA_GUIDS_LIB "@ZIG_DIA_GUIDS_LIB_ESCAPED@"
26
27#endif
src/stage1/zig0.cpp+7-2
......@@ -18,6 +18,11 @@
1818#include "buffer.hpp"
1919#include "os.hpp"
2020
21// This is the only file allowed to include config.h because config.h is
22// only produced when building with cmake. When using the zig build system,
23// zig0.cpp is never touched.
24#include "config.h"
25
2126#include <stdio.h>
2227#include <string.h>
2328
......@@ -539,9 +544,9 @@ const char *stage2_add_link_lib(struct ZigStage1 *stage1,
539544}
540545
541546const char *stage2_version_string(void) {
542 return "0.0.0+zig0";
547 return ZIG_VERSION_STRING;
543548}
544549
545550struct Stage2SemVer stage2_version(void) {
546 return {0, 0, 0};
551 return {ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH};
547552}
src/stage1_config.zig deleted-13
......@@ -1,13 +0,0 @@
1pub const have_llvm = true;
2pub const version: [:0]const u8 = "0.0.0+zig0";
3pub const semver: @import("std").SemanticVersion = .{
4 .major = 0,
5 .minor = 0,
6 .patch = 0,
7 .build = "zig0",
8};
9pub const log_scopes: []const []const u8 = &[_][]const u8{};
10pub const zir_dumps: []const []const u8 = &[_][]const u8{};
11pub const enable_tracy = false;
12pub const is_stage1 = true;
13pub const skip_non_native = false;