├── .github └── workflows │ ├── linux.yml │ ├── macos.yml │ └── windows.yml ├── .gitignore ├── BUILDCONFIG.gn ├── LICENSE ├── README.md ├── README_zh.md ├── config ├── BUILD.gn ├── mac │ └── app_bundle.gni ├── posix │ └── BUILD.gn └── win │ ├── BUILD.gn │ ├── application.gni │ ├── setup_environment.gni │ └── setup_environment.py ├── fetch_binaries.py ├── toolchain ├── linux │ └── BUILD.gn ├── mac │ └── BUILD.gn └── win │ └── BUILD.gn └── tools ├── boost.gni ├── boost.py ├── cmake.gni ├── cmake.py ├── copy.py ├── gn.gni ├── gn.py ├── golang.gni ├── golang.py ├── makefile.gni └── makefile.py /.github/workflows/linux.yml: -------------------------------------------------------------------------------- 1 | name: linux 2 | 3 | on: 4 | push: 5 | pull_request: 6 | release: 7 | types: published 8 | 9 | jobs: 10 | 11 | build: 12 | name: ${{ matrix.os }} ${{ matrix.arch }} ${{ matrix.config }} 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: [ ubuntu-latest ] 17 | arch: [ x64 ] 18 | config: [ debug, release ] 19 | 20 | steps: 21 | 22 | - name: Setup environment 23 | run: | 24 | pip install PyYAML 25 | 26 | - name: Check out gn_toolchain_sample 27 | uses: actions/checkout@v3 28 | with: 29 | repository: Streamlet/gn_toolchain_sample 30 | ref: master 31 | 32 | - name: Check out gn_toolchain 33 | uses: actions/checkout@v3 34 | with: 35 | path: build 36 | 37 | - name: Fetch gn and ninja 38 | run: | 39 | python build/fetch_binaries.py 40 | 41 | - name: Compile 42 | run: | 43 | build/bin/gn gen out/${{ matrix.config }}_${{ matrix.arch }} --args="target_cpu=\"${{ matrix.arch }}\" is_debug=${{ matrix.config == 'debug' }}" 44 | build/bin/ninja -C out/${{ matrix.config }}_${{ matrix.arch }} 45 | -------------------------------------------------------------------------------- /.github/workflows/macos.yml: -------------------------------------------------------------------------------- 1 | name: macos 2 | 3 | on: 4 | push: 5 | pull_request: 6 | release: 7 | types: published 8 | 9 | jobs: 10 | 11 | build: 12 | name: ${{ matrix.os }} ${{ matrix.arch }} ${{ matrix.config }} 13 | runs-on: ${{ matrix.os }} 14 | strategy: 15 | matrix: 16 | os: [ macOS-latest] 17 | arch: [ x64 ] 18 | config: [ debug, release ] 19 | 20 | steps: 21 | 22 | - name: Setup python environment 23 | run: | 24 | pip install PyYAML 25 | 26 | - name: Check out gn_toolchain_sample 27 | uses: actions/checkout@v3 28 | with: 29 | repository: Streamlet/gn_toolchain_sample 30 | ref: master 31 | 32 | - name: Check out gn_toolchain 33 | uses: actions/checkout@v3 34 | with: 35 | path: build 36 | 37 | - name: Fetch gn and ninja 38 | run: | 39 | python build/fetch_binaries.py 40 | 41 | - name: Compile 42 | run: | 43 | build/bin/gn gen out/${{ matrix.config }}_${{ matrix.arch }} --args="target_cpu=\"${{ matrix.arch }}\" is_debug=${{ matrix.config == 'debug' }}" 44 | build/bin/ninja -C out/${{ matrix.config }}_${{ matrix.arch }} 45 | -------------------------------------------------------------------------------- /.github/workflows/windows.yml: -------------------------------------------------------------------------------- 1 | name: windows 2 | 3 | on: 4 | push: 5 | pull_request: 6 | release: 7 | types: published 8 | 9 | jobs: 10 | 11 | build: 12 | name: ${{ matrix.os }} ${{ matrix.arch }} ${{ matrix.config }} 13 | runs-on: ${{ matrix.os }} 14 | defaults: 15 | run: 16 | shell: cmd 17 | strategy: 18 | matrix: 19 | os: [ windows-latest ] 20 | arch: [ x64, x86 ] 21 | config: [ debug, release ] 22 | 23 | steps: 24 | 25 | - name: Setup python environment 26 | run: | 27 | pip install PyYAML 28 | 29 | - name: Check out gn_toolchain_sample 30 | uses: actions/checkout@v3 31 | with: 32 | repository: Streamlet/gn_toolchain_sample 33 | ref: master 34 | 35 | - name: Check out gn_toolchain 36 | uses: actions/checkout@v3 37 | with: 38 | path: build 39 | 40 | - name: Fetch gn and ninja 41 | run: | 42 | python build\\fetch_binaries.py 43 | 44 | - name: Compile 45 | run: | 46 | build\\bin\\gn gen out/${{ matrix.config }}_${{ matrix.arch }} --args="target_cpu=\"${{ matrix.arch }}\" is_debug=${{ matrix.config == 'debug' }}" 47 | build\\bin\\ninja -C out/${{ matrix.config }}_${{ matrix.arch }} 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .* 2 | /bin/ 3 | -------------------------------------------------------------------------------- /BUILDCONFIG.gn: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # PLATFORM SELECTION 3 | # ============================================================================= 4 | 5 | if (target_os == "") { 6 | target_os = host_os 7 | } 8 | 9 | if (target_cpu == "") { 10 | if (target_os == "android") { 11 | # If we're building for Android, we should assume that we want to 12 | # build for ARM by default, not the host_cpu (which is likely x64). 13 | # This allows us to not have to specify both target_os and target_cpu 14 | # on the command line. 15 | target_cpu = "arm" 16 | } else { 17 | target_cpu = host_cpu 18 | } 19 | } 20 | 21 | if (current_cpu == "") { 22 | current_cpu = target_cpu 23 | } 24 | if (current_os == "") { 25 | current_os = target_os 26 | } 27 | 28 | # ============================================================================= 29 | # OS DEFINITIONS 30 | # ============================================================================= 31 | 32 | is_android = current_os == "android" 33 | is_chromeos = current_os == "chromeos" 34 | is_fuchsia = current_os == "fuchsia" 35 | is_ios = current_os == "ios" 36 | is_linux = current_os == "linux" 37 | is_mac = current_os == "mac" 38 | is_nacl = current_os == "nacl" 39 | is_win = current_os == "win" || current_os == "winuwp" 40 | 41 | is_apple = is_ios || is_mac 42 | is_posix = !is_win && !is_fuchsia 43 | 44 | # ============================================================================= 45 | # BUILD FLAGS 46 | # ============================================================================= 47 | 48 | declare_args() { 49 | # Debug build 50 | is_debug = false 51 | } 52 | 53 | declare_args() { 54 | if (is_posix) { 55 | c_std = "gnu17" 56 | cc_std = "gnu++17" 57 | } else { 58 | c_std = "c17" 59 | cc_std = "c++17" 60 | } 61 | } 62 | 63 | declare_args() { 64 | is_winxp = false # targeting to Windows XP 65 | static_link_crt = is_win # static or dynamic link crt 66 | winver = "" # to define WINVER, _WIN32_WINNT and NTDDI_VERSION 67 | } 68 | 69 | if (is_win) { 70 | winver = "0x0A00" 71 | if (is_winxp) { 72 | winver = "0x0501" 73 | } 74 | } 75 | 76 | # ============================================================================== 77 | # TOOLCHAIN SETUP 78 | # ============================================================================== 79 | 80 | if (is_linux) { 81 | set_default_toolchain("//build/toolchain/linux:gcc") 82 | } else if (is_mac) { 83 | set_default_toolchain("//build/toolchain/mac:clang") 84 | } else if (is_win) { 85 | # set environment variables for msvc build tools 86 | import("config/win/setup_environment.gni") 87 | set_default_toolchain("//build/toolchain/win:msvc") 88 | } else { 89 | assert(false, "Unsupported target_os: $target_os") 90 | } 91 | 92 | # ============================================================================= 93 | # TARGET DEFAULTS 94 | # ============================================================================= 95 | 96 | _compile_defaults = [ 97 | "//build/config:default", 98 | "//build/config:c_std", 99 | "//build/config:cc_std", 100 | ] 101 | 102 | if (is_posix) { 103 | _compile_defaults += [ 104 | "//build/config/posix:default", 105 | "//build/config/posix:optmize", 106 | "//build/config/posix:target_arch", 107 | ] 108 | } 109 | 110 | if (is_win) { 111 | _compile_defaults += [ 112 | "//build/config/win:default", 113 | "//build/config/win:optmize", 114 | "//build/config/win:crt_link", 115 | "//build/config/win:core_libraries", 116 | "//build/config/win:win_macros", 117 | "//build/config/win:target_arch", 118 | ] 119 | } 120 | 121 | set_defaults("executable") { 122 | configs = _compile_defaults 123 | if (is_posix) { 124 | configs += [ "//build/config/posix:rpath" ] 125 | } 126 | } 127 | set_defaults("static_library") { 128 | configs = _compile_defaults 129 | } 130 | set_defaults("shared_library") { 131 | configs = _compile_defaults 132 | } 133 | set_defaults("source_set") { 134 | configs = _compile_defaults 135 | } 136 | 137 | # ============================================================================= 138 | # IMPORTS 139 | # ============================================================================= 140 | 141 | # help to build mac app bundle 142 | if (is_mac) { 143 | import("config/mac/app_bundle.gni") 144 | } 145 | 146 | # help to specify subsystem explicitly to build win32 application or console application 147 | if (is_win) { 148 | import("config/win/application.gni") 149 | } 150 | 151 | # help to build nested gn projects 152 | import("tools/gn.gni") 153 | 154 | # help to build makefile projects 155 | import("tools/makefile.gni") 156 | 157 | # help to build cmake projects 158 | import("tools/cmake.gni") 159 | 160 | # help to build boost 161 | import("tools/boost.gni") 162 | 163 | # help to build golang projects 164 | import("tools/golang.gni") 165 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022-2023 Streamlet 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gn toolchain 2 | 3 | ![](https://github.com/Streamlet/gn_toolchain/actions/workflows/windows.yml/badge.svg) ![](https://github.com/Streamlet/gn_toolchain/actions/workflows/linux.yml/badge.svg) ![](https://github.com/Streamlet/gn_toolchain/actions/workflows/macos.yml/badge.svg) 4 | --- 5 | [(中文版本见这里)](README_zh.md) 6 | 7 | This project provides a simple and out-of-the-box gn toolchain configuration, to make cross-platform compile easier under the gn+ninja build system. 8 | 9 | ## Usage 10 | 11 | 1. Put all files of this project into 'build' directory in the root of your project. You could import this project in the form of ordinary folder, submuodule, subtree, or though some dependency manager system, as you wish. 12 | 13 | 2. Create a '.gn' file in the root directory, with content as following: 14 | 15 | ```gn 16 | buildconfig = "//build/BUILDCONFIG.gn" 17 | ``` 18 | 19 | 3. Write your 'BUILD.gn' files for your project, following the rules of gn. 20 | 21 | 4. Run `gn gen out` and `ninja -C out`, to build your project. 22 | 23 | ## Sample 24 | 25 | Please refer to project [gn_toolchain_sample](../../../gn_toolchain_sample). 26 | 27 | ## Fetch gn & ninja 28 | 29 | * Build from source code 30 | * https://gn.googlesource.com/gn 31 | * git://github.com/ninja-build/ninja.git 32 | * Download binaries from official website 33 | * https://gn.googlesource.com/gn/#getting-a-binary 34 | * https://ninja-build.org/ 35 | * Get from package manager. Try package names as following: 36 | * Mac 37 | * Homebrew: (no gn), ninja 38 | * MacPorts: gn-devel, ninja 39 | * Linux 40 | * apt-get & apt: generate-ninja, ninja-build 41 | * yum & dnf: gn, ninja-build 42 | * pacman: gn, ninja 43 | -------------------------------------------------------------------------------- /README_zh.md: -------------------------------------------------------------------------------- 1 | # gn 工具链 2 | 3 | ![](https://github.com/Streamlet/gn_toolchain/actions/workflows/windows.yml/badge.svg) ![](https://github.com/Streamlet/gn_toolchain/actions/workflows/linux.yml/badge.svg) ![](https://github.com/Streamlet/gn_toolchain/actions/workflows/macos.yml/badge.svg) 4 | --- 5 | [(Here is the English Version)](README.md) 6 | 7 | 本项目旨在给出一个简单的、开箱即用的 gn 工具链配置,使得在 gn+ninja 构建系统下的跨平台编译变得更容易。 8 | 9 | ## 用法 10 | 11 | 1. 将本项目所有文件放置到您的项目根目录 ‘build’ 目录中。您可以根据您的需要选择以普通目录形式、submodule 形式、subtree 形式导入本项目,也可以依靠一些依赖处理系统导入本项目。 12 | 13 | 2. 在您的项目根目录建立 ‘.gn’ 文件,内容如下: 14 | 15 | ```gn 16 | buildconfig = "//build/BUILDCONFIG.gn" 17 | ``` 18 | 19 | 3. 按照 gn 规则给您的项目建立 ‘BUILD.gn’ 文件。 20 | 21 | 4. 运行 `gn gen out` 以及 `ninja -C out`,构建项目。 22 | 23 | ## 用例 24 | 25 | 见项目 [gn_toolchain_sample](../../../gn_toolchain_sample)。 26 | 27 | ## 获取 gn & ninja 28 | 29 | * 从源代码编译 30 | * https://gn.googlesource.com/gn 31 | * git://github.com/ninja-build/ninja.git 32 | * 从官方网站下载二进制包 33 | * https://gn.googlesource.com/gn/#getting-a-binary 34 | * https://ninja-build.org/ 35 | * 从包管理器获取,各包管理器的对应包名如下: 36 | * Mac 37 | * Homebrew:(无 gn)、ninja 38 | * MacPorts:gn-devel、ninja 39 | * Linux 40 | * apt-get & apt:generate-ninja、ninja-build 41 | * yum & dnf:gn、ninja-build 42 | * pacman:gn、ninja 43 | -------------------------------------------------------------------------------- /config/BUILD.gn: -------------------------------------------------------------------------------- 1 | # ============================================================================= 2 | # Default 3 | # ============================================================================= 4 | 5 | config("default") { 6 | if (is_debug) { 7 | defines = [ 8 | "DEBUG", 9 | "_DEBUG", 10 | ] 11 | } else { 12 | defines = [ "NDEBUG" ] 13 | } 14 | } 15 | 16 | config("c_std") { 17 | if (is_win) { 18 | if (vs_version >= 150 && !is_winxp) { 19 | cflags_c = [ "/std:$c_std" ] 20 | } 21 | } else { 22 | cflags_c = [ "-std=$c_std" ] 23 | if (is_mac) { 24 | cflags_objc = [ "-std=$c_std" ] 25 | } 26 | } 27 | } 28 | 29 | config("cc_std") { 30 | if (is_win) { 31 | if (vs_version >= 150) { 32 | cflags_cc = [ "/std:$cc_std" ] 33 | } 34 | } else { 35 | cflags_cc = [ "-std=$cc_std" ] 36 | if (is_mac) { 37 | cflags_objcc = [ "-std=$cc_std" ] 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /config/mac/app_bundle.gni: -------------------------------------------------------------------------------- 1 | assert(is_mac) 2 | 3 | template("app_bundle") { 4 | assert(defined(invoker.sources), "Sources must be defined") 5 | assert(defined(invoker.info_plist), "Info.plist must be defined") 6 | 7 | app_name = target_name 8 | 9 | bundle_data("${app_name}_bundle_info_plist") { 10 | sources = [ invoker.info_plist ] 11 | outputs = [ "{{bundle_contents_dir}}/Info.plist" ] 12 | } 13 | 14 | if (defined(invoker.resources) && invoker.resources != []) { 15 | bundle_data("${app_name}_bundle_resources") { 16 | sources = invoker.resources 17 | outputs = [ "{{bundle_resources_dir}}/{{source_file_part}}" ] 18 | } 19 | } 20 | 21 | executable("${app_name}_generate_executable") { 22 | forward_variables_from(invoker, "*", [ "output_name" ]) 23 | output_name = "$app_name" 24 | } 25 | 26 | bundle_data("${app_name}_bundle_executable") { 27 | public_deps = [ ":${app_name}_generate_executable" ] 28 | sources = [ "$root_build_dir/$app_name" ] 29 | outputs = [ "{{bundle_executable_dir}}/$app_name" ] 30 | } 31 | 32 | create_bundle("$app_name.app") { 33 | product_type = "com.apple.product-type.application" 34 | 35 | bundle_root_dir = "$root_build_dir/$target_name" 36 | bundle_contents_dir = "$bundle_root_dir/Contents" 37 | bundle_resources_dir = "$bundle_contents_dir/Resources" 38 | bundle_executable_dir = "$bundle_contents_dir/MacOS" 39 | deps = [ 40 | ":${app_name}_bundle_executable", 41 | ":${app_name}_bundle_info_plist", 42 | ] 43 | if (defined(invoker.resources) && invoker.resources != []) { 44 | deps += [ ":${app_name}_bundle_resources" ] 45 | } 46 | } 47 | 48 | group("$app_name") { 49 | deps = [ ":$app_name.app" ] 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /config/posix/BUILD.gn: -------------------------------------------------------------------------------- 1 | assert(is_posix) 2 | 3 | # ============================================================================= 4 | # Default 5 | # ============================================================================= 6 | 7 | config("default") { 8 | cflags = [ 9 | "-g", 10 | "-fvisibility=hidden", 11 | "-fPIC", 12 | "-pthread", 13 | ] 14 | } 15 | 16 | # ============================================================================= 17 | # Optmize flags 18 | # ============================================================================= 19 | 20 | config("optmize") { 21 | if (is_debug) { 22 | cflags = [ 23 | "-O0", 24 | "-Og", 25 | ] 26 | } else { 27 | cflags = [ "-Ofast" ] 28 | } 29 | } 30 | 31 | # ============================================================================= 32 | # Target arch 33 | # ============================================================================= 34 | 35 | config("target_arch") { 36 | if (target_cpu == "x86") { 37 | cflags = [ "-m32" ] 38 | ldflags = [ "-m32" ] 39 | } else { 40 | cflags = [ "-m64" ] 41 | ldflags = [ "-m64" ] 42 | } 43 | } 44 | 45 | # ============================================================================= 46 | # rpath config 47 | # ============================================================================= 48 | 49 | config("rpath") { 50 | ldflags = [] 51 | if (!is_apple) { 52 | ldflags += [ 53 | "-Wl,-rpath=\$ORIGIN/", 54 | "-Wl,-rpath-link=", 55 | ] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /config/win/BUILD.gn: -------------------------------------------------------------------------------- 1 | assert(is_win) 2 | 3 | # ============================================================================= 4 | # Default 5 | # ============================================================================= 6 | 7 | config("default") { 8 | defines = [ 9 | "UNICODE", 10 | "_UNICODE", 11 | ] 12 | 13 | cflags = [ 14 | "/EHsc", 15 | "/Gd", 16 | "/Gm-", 17 | "/Oy-", 18 | "/W3", 19 | "/WX-", 20 | "/Zi", 21 | "/Zl", 22 | ] 23 | if (vs_version >= 70) { 24 | cflags += [ 25 | "/GS", 26 | "/Zc:forScope", 27 | "/Zc:wchar_t", 28 | ] 29 | } 30 | if (vs_version >= 80) { 31 | cflags += [ 32 | "/analyze-", 33 | "/bigobj", 34 | "/fp:precise", 35 | ] 36 | } 37 | if (vs_version >= 90) { 38 | cflags += [ 39 | "/analyze-", 40 | "/bigobj", 41 | "/fp:precise", 42 | ] 43 | } 44 | if (vs_version >= 140) { 45 | cflags += [ "/utf-8" ] 46 | } 47 | if (vs_version >= 141) { 48 | cflags += [ "/Zc:__cplusplus" ] 49 | } 50 | 51 | cflags_c = [] 52 | cflags_cc = [ "/EHsc" ] 53 | if (vs_version <= 60) { 54 | cflags_c += [ "/TC" ] 55 | cflags_cc += [ "/TP" ] 56 | } 57 | 58 | ldflags = [ 59 | "/DEBUG", 60 | "/NODEFAULTLIB", 61 | ] 62 | if (vs_version >= 110) { 63 | ldflags += [ "/MANIFEST:EMBED" ] 64 | } 65 | } 66 | 67 | # ============================================================================= 68 | # Optmize flags 69 | # ============================================================================= 70 | 71 | config("optmize") { 72 | cflags = [] 73 | if (is_debug) { 74 | cflags += [ "/Od" ] 75 | if (vs_version >= 70) { 76 | cflags += [ "/RTC1" ] 77 | } 78 | if (vs_version >= 158) { 79 | cflags += [ "/JMC" ] 80 | } 81 | } else { 82 | cflags += [ 83 | "/Gy", 84 | "/O2", 85 | "/Oi", 86 | ] 87 | if (vs_version >= 70) { 88 | cflags += [ "/GL" ] 89 | } 90 | } 91 | 92 | ldflags = [] 93 | if (!is_debug) { 94 | ldflags += [ 95 | "/INCREMENTAL:NO", 96 | "/OPT:ICF", 97 | "/OPT:REF", 98 | ] 99 | if (vs_version >= 70) { 100 | ldflags += [ "/LTCG" ] 101 | } 102 | if (vs_version >= 70 && target_cpu == "x86") { 103 | ldflags += [ "/SAFESEH" ] 104 | } 105 | } 106 | 107 | arflags = [] 108 | if (!is_debug && vs_version >= 70) { 109 | arflags += [ "/LTCG" ] 110 | } 111 | } 112 | 113 | # ============================================================================= 114 | # Dynamic or static link CRT 115 | # ============================================================================= 116 | 117 | config("crt_link") { 118 | cflags = [] 119 | if (static_link_crt) { 120 | if (is_debug) { 121 | cflags += [ "/MTd" ] 122 | } else { 123 | cflags += [ "/MT" ] 124 | } 125 | } else { 126 | if (is_debug) { 127 | cflags += [ "/MDd" ] 128 | } else { 129 | cflags += [ "/MD" ] 130 | } 131 | } 132 | 133 | libs = [ "oldnames.lib" ] 134 | if (vs_version >= 140) { 135 | libs += [ 136 | "legacy_stdio_definitions.lib", 137 | "legacy_stdio_wide_specifiers.lib", 138 | ] 139 | } 140 | if (static_link_crt) { 141 | if (is_debug) { 142 | libs += [ 143 | "libcmtd.lib", 144 | "libcpmtd.lib", 145 | ] 146 | if (vs_version >= 140) { 147 | libs += [ 148 | "libvcruntimed.lib", 149 | "libucrtd.lib", 150 | ] 151 | } 152 | } else { 153 | libs += [ 154 | "libcmt.lib", 155 | "libcpmt.lib", 156 | ] 157 | if (vs_version >= 140) { 158 | libs += [ 159 | "libvcruntime.lib", 160 | "libucrt.lib", 161 | ] 162 | } 163 | } 164 | } else { 165 | if (is_debug) { 166 | libs += [ 167 | "msvcrtd.lib", 168 | "msvcprtd.lib", 169 | ] 170 | if (vs_version >= 140) { 171 | libs += [ 172 | "vcruntimed.lib", 173 | "ucrtd.lib", 174 | ] 175 | } 176 | } else { 177 | libs += [ 178 | "msvcrt.lib", 179 | "msvcprt.lib", 180 | ] 181 | if (vs_version >= 140) { 182 | libs += [ 183 | "vcruntime.lib", 184 | "ucrt.lib", 185 | ] 186 | } 187 | } 188 | } 189 | } 190 | 191 | # ============================================================================= 192 | # Core libraries to link default 193 | # ============================================================================= 194 | 195 | config("core_libraries") { 196 | libs = [ 197 | "kernel32.lib", 198 | "user32.lib", 199 | "gdi32.lib", 200 | "winspool.lib", 201 | "comdlg32.lib", 202 | "advapi32.lib", 203 | "shell32.lib", 204 | "ole32.lib", 205 | "oleaut32.lib", 206 | "uuid.lib", 207 | "odbc32.lib", 208 | "odbccp32.lib", 209 | ] 210 | } 211 | 212 | # ============================================================================= 213 | # Defines 214 | # ============================================================================= 215 | 216 | config("win_macros") { 217 | defines = [ 218 | "WINVER=$winver", 219 | "_WIN32_WINNT=$winver", 220 | "_WIN32_WINDOWS=$winver", 221 | "NTDDI_VERSION=${winver}0000", 222 | "WIN32_LEAN_AND_MEAN", 223 | "_CRT_NONSTDC_NO_DEPRECATE", 224 | "_CRT_NONSTDC_NO_WARNINGS", 225 | "_CRT_SECURE_NO_DEPRECATE", 226 | "_CRT_SECURE_NO_WARNINGS", 227 | ] 228 | if (is_winxp) { 229 | defines += [ "_USING_V110_SDK71_" ] 230 | } 231 | } 232 | 233 | # ============================================================================= 234 | # Target arch 235 | # ============================================================================= 236 | 237 | config("target_arch") { 238 | if (target_cpu == "x86") { 239 | ldflags = [ "/MACHINE:X86" ] 240 | arflags = [ "/MACHINE:X86" ] 241 | } else { 242 | assert(vs_version >= 80) 243 | ldflags = [ "/MACHINE:X64" ] 244 | arflags = [ "/MACHINE:X64" ] 245 | } 246 | } 247 | 248 | # ============================================================================= 249 | # Console or windows subsystem 250 | # ============================================================================= 251 | 252 | config("console_subsystem") { 253 | if (target_cpu == "x86") { 254 | ldflags = [ "/SUBSYSTEM:CONSOLE,5.01" ] 255 | arflags = [ "/SUBSYSTEM:CONSOLE,5.01" ] 256 | } else { 257 | ldflags = [ "/SUBSYSTEM:CONSOLE,5.02" ] 258 | arflags = [ "/SUBSYSTEM:CONSOLE,5.02" ] 259 | } 260 | } 261 | 262 | config("windows_subsystem") { 263 | if (target_cpu == "x86") { 264 | ldflags = [ "/SUBSYSTEM:WINDOWS,5.01" ] 265 | arflags = [ "/SUBSYSTEM:WINDOWS,5.01" ] 266 | } else { 267 | ldflags = [ "/SUBSYSTEM:WINDOWS,5.02" ] 268 | arflags = [ "/SUBSYSTEM:WINDOWS,5.02" ] 269 | } 270 | } 271 | -------------------------------------------------------------------------------- /config/win/application.gni: -------------------------------------------------------------------------------- 1 | assert(is_win) 2 | 3 | template("console_app") { 4 | executable("$target_name") { 5 | forward_variables_from(invoker, "*", []) 6 | configs += [ "//build/config/win:console_subsystem" ] 7 | } 8 | } 9 | 10 | template("win32_app") { 11 | executable("$target_name") { 12 | forward_variables_from(invoker, "*", []) 13 | configs += [ "//build/config/win:windows_subsystem" ] 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /config/win/setup_environment.gni: -------------------------------------------------------------------------------- 1 | assert(is_win) 2 | 3 | declare_args() { 4 | vs_version = "" 5 | clang_installed = false 6 | msvc_installed = false 7 | } 8 | 9 | env = exec_script("setup_environment.py", 10 | [ 11 | host_cpu, 12 | target_cpu, 13 | "$is_winxp", 14 | ], 15 | "scope") 16 | 17 | vs_version = env.VERSION 18 | clang_installed = env.CLANG 19 | msvc_installed = env.MSVC 20 | -------------------------------------------------------------------------------- /config/win/setup_environment.py: -------------------------------------------------------------------------------- 1 | import os 2 | import sys 3 | import locale 4 | import subprocess 5 | import re 6 | 7 | 8 | VC_60_VERSION = 60 9 | VS_2002_VERSION = 70 10 | VS_2003_VERSION = 71 11 | VS_2005_VERSION = 80 12 | VS_2008_VERSION = 90 13 | VS_2010_VERSION = 100 14 | VS_2012_VERSION = 110 15 | VS_2013_VERSION = 120 16 | VS_2015_VERSION = 140 17 | VS_2017_VERSION = 150 18 | VS_2019_VERSION = 160 19 | VS_2022_VERSION = 170 20 | 21 | 22 | def ExecuteCmd(cmd): 23 | encoding = locale.getpreferredencoding(False) 24 | (stdoutdata, stderrdata) = subprocess.Popen( 25 | cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT 26 | ).communicate() 27 | if stderrdata is not None: 28 | print(stderrdata.decode(encoding)) 29 | return False 30 | output = stdoutdata.decode(encoding) 31 | return output.strip() 32 | 33 | 34 | def DetectSetEnvBatchFileByVSWhere(host_cpu, target_cpu): 35 | program_files_x86 = os.environ['ProgramFiles(x86)'] 36 | vswhere_path = os.path.join( 37 | program_files_x86, 'Microsoft Visual Studio', 'Installer', 'vswhere.exe') 38 | if not os.path.exists(vswhere_path): 39 | return None, None 40 | cmd = '"%s" -latest -property installationPath' % vswhere_path 41 | vs_path = ExecuteCmd(cmd) 42 | if vs_path is None or vs_path == '': 43 | return None, None 44 | cmd = '"%s" -latest -property installationVersion' % vswhere_path 45 | vs_version_string = ExecuteCmd(cmd) 46 | if vs_version_string is None or vs_version_string == '': 47 | return None, None 48 | vs_version_part = list(map(lambda x: int(x), vs_version_string.split('.'))) 49 | if len(vs_version_part) < 2: 50 | return None, None 51 | vs_version = vs_version_part[0] * 10 + (min(vs_version_part[1], 9)) 52 | batch_file = os.path.join( 53 | vs_path, 'VC', 'Auxiliary', 'Build', 'vcvarsall.bat') 54 | if not os.path.exists(batch_file): 55 | return None, None 56 | if host_cpu == target_cpu: 57 | arch = target_cpu 58 | else: 59 | arch = host_cpu + '_' + target_cpu 60 | return vs_version, [batch_file, arch] 61 | 62 | 63 | def DetectSetEnvBatchFileByEnvVar(host_cpu, target_cpu): 64 | regex = re.compile(r'VS(\d+)COMNTOOLS') 65 | vs_versions = [] 66 | for vs in os.environ: 67 | m = regex.match(vs.upper()) 68 | if m: 69 | vs_versions.append((int(m.group(1)), os.environ[vs])) 70 | vs_versions = sorted(vs_versions, key=lambda item: item[0], reverse=True) 71 | for version, path in vs_versions: 72 | if version > VS_2003_VERSION: 73 | batch_file = os.path.join(path, '..', '..', 'VC', 'vcvarsall.bat') 74 | if os.path.exists(batch_file): 75 | return version, '"' + batch_file + '" ' + target_cpu 76 | else: 77 | batch_file = os.path.join(path, 'vsvars32.bat') 78 | if os.path.exists(batch_file): 79 | return version, [batch_file] 80 | return None, None 81 | 82 | 83 | def DetectSetEnvBatchFileByFindVC6(host_cpu, target_cpu): 84 | program_files_x86 = os.environ['ProgramFiles(x86)'] 85 | batch_file = os.path.join( 86 | program_files_x86, 'Microsoft Visual Studio', 'VC98', 'Bin', 'vcvars32.bat') 87 | if not os.path.exists(batch_file): 88 | return None, None 89 | return VC_60_VERSION, [batch_file] 90 | 91 | 92 | def FindWinSDK71(host_cpu, target_cpu): 93 | program_files_x86 = os.environ['ProgramFiles(x86)'] 94 | sdk_dir = os.path.join( 95 | program_files_x86, 'Microsoft SDKs', 'Windows', 'v7.1A') 96 | include_path = os.path.join(sdk_dir, 'Include') 97 | lib_path = os.path.join(sdk_dir, 'Lib') 98 | if target_cpu == 'x64': 99 | lib_path = os.path.join(lib_path, 'x64') 100 | if not os.path.exists(include_path) or not os.path.exists(lib_path): 101 | return None, None 102 | return include_path, lib_path 103 | 104 | 105 | def SetupEnvironment(host_cpu, target_cpu, is_winxp): 106 | version, cmd = DetectSetEnvBatchFileByVSWhere(host_cpu, target_cpu) 107 | if cmd is None: 108 | version, cmd = DetectSetEnvBatchFileByEnvVar(host_cpu, target_cpu) 109 | if cmd is None: 110 | version, cmd = DetectSetEnvBatchFileByFindVC6(host_cpu, target_cpu) 111 | if cmd is None: 112 | assert False, 'Cannot fine Windows SDK set-env batch file' 113 | if is_winxp: 114 | include_path, lib_path = FindWinSDK71(host_cpu, target_cpu) 115 | if include_path is None or lib_path is None: 116 | assert False, 'Cannot Windows SDK v7.1A, please make sure it is installed.' 117 | shell_cmd = '"%s" %s && Set' % (cmd[0], ' '.join(cmd[1:])) 118 | env_lines = ExecuteCmd(shell_cmd) 119 | ENV_VAR_TO_SAVE = ( 120 | 'INCLUDE', 121 | 'LIB', 122 | 'LIBPATH', 123 | 'PATH', 124 | 'PATHEXT', 125 | 'SYSTEMROOT', 126 | 'TEMP', 127 | 'TMP', 128 | ) 129 | env = {} 130 | for line in env_lines.split('\n'): 131 | kv = line.split('=', 2) 132 | if kv[0].upper() in ENV_VAR_TO_SAVE: 133 | env[kv[0].upper()] = kv[1].strip() 134 | if is_winxp: 135 | if version > VS_2017_VERSION: 136 | vc141_version_file = os.path.join(os.path.dirname( 137 | cmd[0]), 'Microsoft.VCToolsVersion.v141.default.txt') 138 | vc_version_file = os.path.join(os.path.dirname( 139 | cmd[0]), 'Microsoft.VCToolsVersion.default.txt') 140 | if not os.path.exists(vc141_version_file): 141 | assert False, 'v141_xp toolset not installed' 142 | with open(vc141_version_file, 'r') as f: 143 | vc141_version = f.read().strip() 144 | with open(vc_version_file, 'r') as f: 145 | vc_version = f.read().strip() 146 | env['INCLUDE'] = env['INCLUDE'].replace(vc_version, vc141_version) 147 | env['LIB'] = env['LIB'].replace(vc_version, vc141_version) 148 | env['LIBPATH'] = env['LIBPATH'].replace(vc_version, vc141_version) 149 | env['PATH'] = env['PATH'].replace(vc_version, vc141_version) 150 | 151 | env['INCLUDE'] = include_path + ';' + env['INCLUDE'] 152 | env['LIB'] = lib_path + ';' + env['LIB'] 153 | env['LIBPATH'] = lib_path + ';' + env['LIBPATH'] 154 | 155 | env_file_content = '' 156 | for k in env: 157 | env_file_content += k + '=' + env[k] + '\0' 158 | env_file_content += '\0' 159 | with open('environment.%s.%s' % (host_cpu, target_cpu), 'w') as f: 160 | f.write(env_file_content) 161 | return version, env 162 | 163 | 164 | def FindExecutableInPath(env_path, exe_name): 165 | paths = env_path.split(';') 166 | for path in paths: 167 | if os.path.exists(os.path.join(path, exe_name)): 168 | return path 169 | return None 170 | 171 | 172 | def FindCompiles(env_path): 173 | cl_path = FindExecutableInPath(env_path, 'cl.exe') 174 | clang_path = FindExecutableInPath(env_path, 'clang.exe') 175 | return {'MSVC': cl_path, 'CLANG': clang_path} 176 | 177 | 178 | def main(): 179 | (host_cpu, target_cpu, is_winxp) = sys.argv[1:] 180 | version, env = SetupEnvironment(host_cpu, target_cpu, is_winxp == 'true') 181 | print('VERSION = %s' % version) 182 | cc_path = FindCompiles(env['PATH']) 183 | for cc in cc_path: 184 | print('%s = %s' % (cc, 'true' if cc_path[cc] is not None else 'false')) 185 | 186 | 187 | if __name__ == '__main__': 188 | main() 189 | -------------------------------------------------------------------------------- /fetch_binaries.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | import zipfile 7 | import stat 8 | if sys.version >= '3': 9 | import urllib.request as urllib 10 | else: 11 | import urllib 12 | 13 | 14 | def get_redirected_url(url): 15 | try: 16 | remote = urllib.urlopen(url) 17 | except Exception as e: 18 | print(e) 19 | return None 20 | return remote.url 21 | 22 | 23 | def download(url, file): 24 | if not os.path.exists(os.path.dirname(file)): 25 | os.makedirs(os.path.dirname(file)) 26 | try: 27 | remote = urllib.urlopen(url) 28 | except Exception as e: 29 | print(e) 30 | return False 31 | with open(file, 'wb') as local: 32 | BLOCK_SIZE = 1024 * 1024 33 | while True: 34 | buffer = remote.read(BLOCK_SIZE) 35 | local.write(buffer) 36 | if len(buffer) < BLOCK_SIZE: 37 | break 38 | return True 39 | 40 | 41 | def main(): 42 | os.chdir(os.path.dirname(__file__)) 43 | 44 | ninja_latest = os.path.basename(get_redirected_url( 45 | 'https://github.com/ninja-build/ninja/releases/latest')) 46 | url = {} 47 | if sys.platform == 'win32': 48 | url['gn'] = 'https://chrome-infra-packages.appspot.com/dl/gn/gn/windows-amd64/+/latest' 49 | url['ninja'] = 'https://github.com/ninja-build/ninja/releases/download/%s/ninja-win.zip' % ninja_latest 50 | elif sys.platform == 'darwin': 51 | url['gn'] = 'https://chrome-infra-packages.appspot.com/dl/gn/gn/mac-amd64/+/latest' 52 | url['ninja'] = 'https://github.com/ninja-build/ninja/releases/download/%s/ninja-mac.zip' % ninja_latest 53 | elif sys.platform == 'linux': 54 | url['gn'] = 'https://chrome-infra-packages.appspot.com/dl/gn/gn/linux-amd64/+/latest' 55 | url['ninja'] = 'https://github.com/ninja-build/ninja/releases/download/%s/ninja-linux.zip' % ninja_latest 56 | else: 57 | assert False, 'Unsupport system: %s' % sys.platform 58 | 59 | for t in ('gn', 'ninja',): 60 | z = os.path.join('bin', t + '.zip') 61 | download(url[t], z) 62 | with zipfile.ZipFile(z, 'r') as zip: 63 | f = t + '.exe' if sys.platform == 'win32' else t 64 | zip.extract(f, 'bin') 65 | if sys.platform != 'win32': 66 | p = os.path.join('bin', f) 67 | st = os.stat(p) 68 | os.chmod(p, st.st_mode | stat.S_IEXEC) 69 | os.remove(z) 70 | 71 | 72 | if __name__ == '__main__': 73 | main() 74 | -------------------------------------------------------------------------------- /toolchain/linux/BUILD.gn: -------------------------------------------------------------------------------- 1 | toolchain("gcc") { 2 | cc = "gcc" 3 | cxx = "g++" 4 | asm = cc 5 | ar = "ar" 6 | ld = cxx 7 | 8 | md = "-MMD" 9 | 10 | # These library switches can apply to all tools below. 11 | lib_switch = "-l" 12 | lib_dir_switch = "-L" 13 | 14 | # Object files go in this directory. 15 | object_subdir = "{{target_out_dir}}/{{label_name}}" 16 | 17 | tool("cc") { 18 | depfile = "{{output}}.d" 19 | precompiled_header_type = "gcc" 20 | command = "$cc $md -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" 21 | depsformat = "gcc" 22 | description = "CC {{output}}" 23 | outputs = [ "$object_subdir/{{source_name_part}}.o" ] 24 | } 25 | tool("cxx") { 26 | depfile = "{{output}}.d" 27 | precompiled_header_type = "gcc" 28 | command = "$cxx $md -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" 29 | depsformat = "gcc" 30 | description = "CXX {{output}}" 31 | outputs = [ "$object_subdir/{{source_name_part}}.o" ] 32 | } 33 | tool("asm") { 34 | # For GCC we can just use the C compiler to compile assembly. 35 | depfile = "{{output}}.d" 36 | command = "$asm $md -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" 37 | depsformat = "gcc" 38 | description = "ASM {{output}}" 39 | outputs = [ "$object_subdir/{{source_name_part}}.o" ] 40 | } 41 | tool("alink") { 42 | rspfile = "{{output}}.rsp" 43 | rspfile_content = "{{inputs}}" 44 | command = "\"$ar\" {{arflags}} -r -c -s -D {{output}} @\"$rspfile\"" 45 | command = "rm -f {{output}} && $command" 46 | description = "AR {{output}}" 47 | outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] 48 | 49 | # Shared libraries go in the target out directory by default so we can 50 | # generate different targets with the same name and not have them collide. 51 | default_output_dir = "{{root_out_dir}}" 52 | default_output_extension = ".a" 53 | output_prefix = "lib" 54 | } 55 | tool("solink") { 56 | soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". 57 | sofile = "{{output_dir}}/$soname" # Possibly including toolchain dir. 58 | rspfile = sofile + ".rsp" 59 | soname_flag = "-Wl,-soname=\"$soname\"" 60 | command = 61 | "$ld -shared $soname_flag {{ldflags}} -o \"$sofile\" @\"$rspfile\"" 62 | rspfile_content = "-Wl,--whole-archive {{inputs}} {{solibs}} -Wl,--no-whole-archive {{libs}} -Wl,--whole-archive {{rlibs}} -Wl,--no-whole-archive" 63 | description = "SOLINK $sofile" 64 | default_output_dir = "{{root_out_dir}}" 65 | default_output_extension = ".so" 66 | output_prefix = "lib" 67 | 68 | # Since the above commands only updates the .TOC file when it changes, ask 69 | # Ninja to check if the timestamp actually changed to know if downstream 70 | # dependencies should be recompiled. 71 | restat = true 72 | 73 | # Tell GN about the output files. It will link to the sofile but use the 74 | # tocfile for dependency management. 75 | outputs = [ sofile ] 76 | link_output = sofile 77 | depend_output = sofile 78 | } 79 | tool("solink_module") { 80 | soname = "{{target_output_name}}{{output_extension}}" # e.g. "libfoo.so". 81 | sofile = "{{output_dir}}/$soname" 82 | rspfile = sofile + ".rsp" 83 | soname_flag = "-Wl,-soname=\"$soname\"" 84 | whole_archive_flag = "-Wl,--whole-archive" 85 | no_whole_archive_flag = "-Wl,--no-whole-archive" 86 | command = 87 | "$ld -shared {{ldflags}} -o \"$sofile\" $soname_flag @\"$rspfile\"" 88 | rspfile_content = "$whole_archive_flag {{inputs}} {{solibs}} $no_whole_archive_flag {{libs}} $whole_archive_flag {{rlibs}} $no_whole_archive_flag" 89 | description = "SOLINK_MODULE $sofile" 90 | default_output_dir = "{{root_out_dir}}" 91 | default_output_extension = ".so" 92 | output_prefix = "lib" 93 | outputs = [ sofile ] 94 | } 95 | tool("link") { 96 | exename = "{{target_output_name}}{{output_extension}}" 97 | outfile = "{{output_dir}}/$exename" 98 | rspfile = "$outfile.rsp" 99 | default_output_dir = "{{root_out_dir}}" 100 | start_group_flag = "-Wl,--start-group" 101 | end_group_flag = "-Wl,--end-group " 102 | link_command = "$ld {{ldflags}} -o \"$outfile\" $start_group_flag @\"$rspfile\" {{solibs}} $end_group_flag {{libs}}" 103 | command = "$link_command" 104 | description = "LINK $outfile" 105 | whole_archive_flag = "-Wl,--whole-archive" 106 | no_whole_archive_flag = "-Wl,--no-whole-archive" 107 | rspfile_content = 108 | "{{inputs}} $whole_archive_flag {{rlibs}} $no_whole_archive_flag " 109 | outputs = [ outfile ] 110 | } 111 | tool("stamp") { 112 | command = "touch {{output}}" 113 | description = "STAMP {{output}}" 114 | } 115 | tool("copy") { 116 | command = "cp -af {{source}} {{output}}" 117 | description = "COPY {{source}} {{output}}" 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /toolchain/mac/BUILD.gn: -------------------------------------------------------------------------------- 1 | toolchain("clang") { 2 | cc = "clang" 3 | cxx = "clang++" 4 | ld = cxx 5 | 6 | # Use explicit paths to binaries. The binaries present on the default 7 | # search path in /usr/bin are thin wrappers around xcrun, which requires a 8 | # full CommandLineTools or Xcode install, and still may not choose the 9 | # appropriate binary if there are multiple installs. 10 | if (host_os == "mac") { 11 | libtool = "libtool" 12 | nm = "nm" 13 | otool = "otool" 14 | } else { 15 | ar = "llvm-ar" 16 | nm = "llvm-nm" 17 | otool = "llvm-otool" 18 | } 19 | 20 | # Make these apply to all tools below. 21 | lib_switch = "-l" 22 | lib_dir_switch = "-L" 23 | 24 | # Object files go in this directory. Use label_name instead of 25 | # target_output_name since labels will generally have no spaces and will be 26 | # unique in the directory. 27 | object_subdir = "{{target_out_dir}}/{{label_name}}" 28 | 29 | # If dSYMs are enabled, this flag will be added to the link tools. 30 | linker_out = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 31 | dsym_output_dir = 32 | "{{root_out_dir}}/{{target_output_name}}{{output_extension}}.dSYM" 33 | dsymutil_comand = "dsymutil -o $dsym_output_dir $linker_out" 34 | strip_command = "strip -x -S $linker_out" 35 | dsym_switch = "$dsymutil_comand && $strip_command" 36 | 37 | dsym_output = [ 38 | "$dsym_output_dir/Contents/Info.plist", 39 | "$dsym_output_dir/Contents/Resources/DWARF/{{target_output_name}}{{output_extension}}", 40 | ] 41 | 42 | tool("cc") { 43 | depfile = "{{output}}.d" 44 | precompiled_header_type = "gcc" 45 | command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} -c {{source}} -o {{output}}" 46 | depsformat = "gcc" 47 | description = "CC {{output}}" 48 | outputs = [ "$object_subdir/{{source_name_part}}.o" ] 49 | } 50 | 51 | tool("cxx") { 52 | depfile = "{{output}}.d" 53 | precompiled_header_type = "gcc" 54 | command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} -c {{source}} -o {{output}}" 55 | depsformat = "gcc" 56 | description = "CXX {{output}}" 57 | outputs = [ "$object_subdir/{{source_name_part}}.o" ] 58 | } 59 | 60 | tool("asm") { 61 | # For GCC we can just use the C compiler to compile assembly. 62 | depfile = "{{output}}.d" 63 | command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{asmflags}} -c {{source}} -o {{output}}" 64 | depsformat = "gcc" 65 | description = "ASM {{output}}" 66 | outputs = [ "$object_subdir/{{source_name_part}}.o" ] 67 | } 68 | 69 | tool("objc") { 70 | depfile = "{{output}}.d" 71 | precompiled_header_type = "gcc" 72 | command = "$cc -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objc}} -c {{source}} -o {{output}}" 73 | depsformat = "gcc" 74 | description = "OBJC {{output}}" 75 | outputs = [ "$object_subdir/{{source_name_part}}.o" ] 76 | } 77 | 78 | tool("objcxx") { 79 | depfile = "{{output}}.d" 80 | precompiled_header_type = "gcc" 81 | command = "$cxx -MMD -MF $depfile {{defines}} {{include_dirs}} {{framework_dirs}} {{cflags}} {{cflags_objcc}} -c {{source}} -o {{output}}" 82 | depsformat = "gcc" 83 | description = "OBJCXX {{output}}" 84 | outputs = [ "$object_subdir/{{source_name_part}}.o" ] 85 | } 86 | 87 | tool("alink") { 88 | rspfile = "{{output}}.rsp" 89 | rspfile_content = "{{inputs}}" 90 | 91 | if (host_os == "mac") { 92 | command = "rm -f {{output}} && $libtool -static -D {{arflags}} -o {{output}} @$rspfile" 93 | description = "LIBTOOL-STATIC {{output}}" 94 | } else { 95 | command = "$ar {{arflags}} -r -c -s -D {{output}} @$rspfile" 96 | 97 | # Remove the output file first so that ar doesn't try to modify the 98 | # existing file. 99 | command = "rm -f {{output}} && $command" 100 | description = "AR {{output}}" 101 | } 102 | 103 | outputs = [ "{{output_dir}}/{{target_output_name}}{{output_extension}}" ] 104 | default_output_dir = "{{root_out_dir}}" 105 | default_output_extension = ".a" 106 | output_prefix = "lib" 107 | } 108 | tool("solink") { 109 | # E.g. "./libfoo.dylib": 110 | dylib = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 111 | rspfile = dylib + ".rsp" 112 | 113 | # These variables are not built into GN but are helpers that implement 114 | # (1) linking to produce a .dylib, (2) extracting the symbols from that 115 | # file to a temporary file, (3) if the temporary file has differences from 116 | # the existing .TOC file, overwrite it, otherwise, don't change it. 117 | # 118 | # As a special case, if the library reexports symbols from other dynamic 119 | # libraries, we always update the .TOC and skip the temporary file and 120 | # diffing steps, since that library always needs to be re-linked. 121 | tocname = dylib + ".TOC" 122 | temporary_tocname = dylib + ".tmp" 123 | 124 | does_reexport_command = "[ ! -e \"$dylib\" -o ! -e \"$tocname\" ] || $otool -l \"$dylib\" | grep -q LC_REEXPORT_DYLIB" 125 | 126 | link_command = 127 | "$ld -shared {{ldflags}} -o \"$dylib\" \"@$rspfile\" && $dsym_switch" 128 | replace_command = "if ! cmp -s \"$temporary_tocname\" \"$tocname\"; then mv \"$temporary_tocname\" \"$tocname\"" 129 | extract_toc_command = "{ $otool -l \"$dylib\" | grep LC_ID_DYLIB -A 5; $nm -gPp \"$dylib\" | cut -f1-2 -d' ' | grep -v U\$\$; true; }" 130 | 131 | command = "if $does_reexport_command ; then $link_command && $extract_toc_command > \"$tocname\"; else $link_command && $extract_toc_command > \"$temporary_tocname\" && $replace_command ; fi; fi" 132 | 133 | rspfile_content = "{{inputs}} {{frameworks}} {{solibs}} {{libs}} {{rlibs}}" 134 | 135 | description = "SOLINK {{output}}" 136 | 137 | # Use this for {{output_extension}} expansions unless a target manually 138 | # overrides it (in which case {{output_extension}} will be what the target 139 | # specifies). 140 | default_output_dir = "{{root_out_dir}}" 141 | default_output_extension = ".dylib" 142 | 143 | output_prefix = "lib" 144 | 145 | # Since the above commands only updates the .TOC file when it changes, ask 146 | # Ninja to check if the timestamp actually changed to know if downstream 147 | # dependencies should be recompiled. 148 | restat = true 149 | 150 | # Tell GN about the output files. It will link to the dylib but use the 151 | # tocname for dependency management. 152 | outputs = [ 153 | dylib, 154 | tocname, 155 | ] 156 | outputs += dsym_output 157 | link_output = dylib 158 | depend_output = tocname 159 | } 160 | tool("solink_module") { 161 | # E.g. "./libfoo.so": 162 | sofile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 163 | rspfile = sofile + ".rsp" 164 | 165 | link_command = 166 | "$ld -bundle {{ldflags}} -o \"$sofile\" \"@$rspfile\" && $dsym_switch" 167 | command = link_command 168 | 169 | rspfile_content = "{{inputs}} {{frameworks}} {{solibs}} {{libs}} {{rlibs}}" 170 | 171 | description = "SOLINK_MODULE {{output}}" 172 | 173 | # Use this for {{output_extension}} expansions unless a target manually 174 | # overrides it (in which case {{output_extension}} will be what the target 175 | # specifies). 176 | default_output_dir = "{{root_out_dir}}" 177 | default_output_extension = ".so" 178 | 179 | outputs = [ sofile ] 180 | outputs += dsym_output 181 | } 182 | tool("link") { 183 | outfile = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 184 | rspfile = "$outfile.rsp" 185 | 186 | command = "$ld {{ldflags}} -o \"$outfile\" \"@$rspfile\" && $dsym_switch" 187 | description = "LINK $outfile" 188 | rspfile_content = "{{inputs}} {{frameworks}} {{solibs}} {{libs}} {{rlibs}}" 189 | 190 | outputs = [ outfile ] 191 | outputs += dsym_output 192 | default_output_dir = "{{root_out_dir}}" 193 | } 194 | tool("stamp") { 195 | command = "touch {{output}}" 196 | description = "STAMP {{output}}" 197 | } 198 | tool("copy") { 199 | command = "cp -af {{source}} {{output}}" 200 | description = "COPY {{source}} {{output}}" 201 | } 202 | tool("copy_bundle_data") { 203 | # copy_command use hardlink if possible but this does not work with 204 | # directories. Also when running EG2 tests from Xcode, Xcode tries to 205 | # copy some files into the application bundle which fails if source 206 | # and destination are hardlinked together. 207 | # 208 | # Instead use clonefile to copy the files which is as efficient as 209 | # hardlink but ensure the file have distinct metadata (thus avoid the 210 | # error with ditto, see https://crbug.com/1042182). 211 | if (host_os == "mac") { 212 | command = "rm -rf {{output}} && cp -Rc {{source}} {{output}}" 213 | } else { 214 | command = "rm -rf {{output}} && cp -Rl {{source}} {{output}}" 215 | } 216 | description = "COPY_BUNDLE_DATA {{source}} {{output}}" 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /toolchain/win/BUILD.gn: -------------------------------------------------------------------------------- 1 | toolchain("msvc") { 2 | cl = "cl.exe" 3 | rc = "rc.exe" 4 | lib = "lib.exe" 5 | link = "link.exe" 6 | 7 | if (target_cpu == "x64") { 8 | ml = "ml64.exe" 9 | } else { 10 | ml = "ml.exe" 11 | } 12 | 13 | env = "environment." + host_cpu + "." + target_cpu 14 | env_wrappper = "ninja -t msvc -e $env --" 15 | 16 | # Make these apply to all tools below. 17 | lib_switch = "" 18 | lib_dir_switch = "/LIBPATH:" 19 | 20 | # Object files go in this directory. 21 | object_subdir = "{{target_out_dir}}/{{label_name}}" 22 | 23 | copy_script = rebase_path("../../tools/copy.py", root_build_dir) 24 | 25 | tool("cc") { 26 | precompiled_header_type = "msvc" 27 | pdbname = "{{target_out_dir}}/{{label_name}}_c.pdb" 28 | 29 | # Label names may have spaces in them so the pdbname must be quoted. The 30 | # source and output don't need to be quoted because GN knows they're a 31 | # full file name and will quote automatically when necessary. 32 | depsformat = "msvc" 33 | description = "CC {{output}}" 34 | outputs = [ "$object_subdir/{{source_name_part}}.obj" ] 35 | 36 | if (vs_version >= 120) { 37 | command = "$env_wrappper $cl /c {{source}} /nologo {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} /Fo{{output}} /Fd\"$pdbname\" /FS" 38 | } else { 39 | command = "$env_wrappper $cl /c {{source}} /nologo {{defines}} {{include_dirs}} {{cflags}} {{cflags_c}} /Fo{{output}} /Fd\"$pdbname\"" 40 | } 41 | } 42 | tool("cxx") { 43 | precompiled_header_type = "msvc" 44 | 45 | # The PDB name needs to be different between C and C++ compiled files. 46 | pdbname = "{{target_out_dir}}/{{label_name}}_cc.pdb" 47 | 48 | # See comment in CC tool about quoting. 49 | depsformat = "msvc" 50 | description = "CXX {{output}}" 51 | outputs = [ "$object_subdir/{{source_name_part}}.obj" ] 52 | 53 | if (vs_version >= 120) { 54 | command = "$env_wrappper $cl /c {{source}} /Fo{{output}} /nologo {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} /Fd\"$pdbname\" /FS" 55 | } else { 56 | command = "$env_wrappper $cl /c {{source}} /Fo{{output}} /nologo {{defines}} {{include_dirs}} {{cflags}} {{cflags_cc}} /Fd\"$pdbname\"" 57 | } 58 | } 59 | tool("rc") { 60 | if (vs_version >= 100) { 61 | command = "$env_wrappper $rc /nologo {{defines}} {{include_dirs}} /fo{{output}} {{source}}" 62 | } else { 63 | command = "$env_wrappper $rc {{defines}} {{include_dirs}} /fo{{output}} {{source}}" 64 | } 65 | depsformat = "msvc" 66 | outputs = [ "$object_subdir/{{source_name_part}}.res" ] 67 | description = "RC {{output}}" 68 | } 69 | tool("asm") { 70 | command = "$env_wrappper $ml /nologo /c /Fo{{output}} {{defines}} {{include_dirs}} {{asmflags}} {{source}}" 71 | description = "ASM {{output}}" 72 | outputs = [ "$object_subdir/{{source_name_part}}.obj" ] 73 | } 74 | tool("alink") { 75 | rspfile = "{{output}}.rsp" 76 | command = "$env_wrappper $lib /OUT:{{output}} /nologo {{arflags}} @$rspfile" 77 | description = "LIB {{output}}" 78 | outputs = [ 79 | # Ignore {{output_extension}} and always use .lib, there's no reason to 80 | # allow targets to override this extension on Windows. 81 | "{{output_dir}}/{{target_output_name}}.lib", 82 | ] 83 | default_output_extension = ".lib" 84 | default_output_dir = "{{root_out_dir}}" 85 | 86 | # The use of inputs_newline is to work around a fixed per-line buffer 87 | # size in the linker. 88 | rspfile_content = "{{inputs_newline}}" 89 | } 90 | tool("solink") { 91 | # E.g. "foo.dll": 92 | dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 93 | libname = "${dllname}.lib" # e.g. foo.dll.lib 94 | pdbname = "${dllname}.pdb" 95 | rspfile = "${dllname}.rsp" 96 | 97 | command = "$env_wrappper $link {{ldflags}} /OUT:$dllname /nologo /IMPLIB:$libname /DLL /PDB:$pdbname @$rspfile" 98 | 99 | default_output_extension = ".dll" 100 | default_output_dir = "{{root_out_dir}}" 101 | description = "LINK(DLL) {{output}}" 102 | outputs = [ 103 | dllname, 104 | libname, 105 | pdbname, 106 | ] 107 | link_output = libname 108 | depend_output = libname 109 | runtime_outputs = [ 110 | dllname, 111 | pdbname, 112 | ] 113 | 114 | # Since the above commands only updates the .lib file when it changes, 115 | # ask Ninja to check if the timestamp actually changed to know if 116 | # downstream dependencies should be recompiled. 117 | restat = true 118 | 119 | # The use of inputs_newline is to work around a fixed per-line buffer 120 | # size in the linker. 121 | rspfile_content = "{{libs}} {{solibs}} {{inputs_newline}} {{rlibs}}" 122 | } 123 | tool("solink_module") { 124 | # E.g. "foo.dll": 125 | dllname = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 126 | pdbname = "${dllname}.pdb" 127 | rspfile = "${dllname}.rsp" 128 | 129 | command = "$env_wrappper $link {{ldflags}} /OUT:$dllname /nologo /DLL /PDB:$pdbname @$rspfile" 130 | 131 | default_output_extension = ".dll" 132 | default_output_dir = "{{root_out_dir}}" 133 | description = "LINK_MODULE(DLL) {{output}}" 134 | outputs = [ 135 | dllname, 136 | pdbname, 137 | ] 138 | runtime_outputs = outputs 139 | 140 | # The use of inputs_newline is to work around a fixed per-line buffer 141 | # size in the linker. 142 | rspfile_content = "{{libs}} {{solibs}} {{inputs_newline}} {{rlibs}}" 143 | } 144 | tool("link") { 145 | exename = "{{output_dir}}/{{target_output_name}}{{output_extension}}" 146 | pdbname = "$exename.pdb" 147 | rspfile = "$exename.rsp" 148 | 149 | command = "$env_wrappper $link {{ldflags}} /OUT:$exename /nologo /PDB:$pdbname @$rspfile" 150 | 151 | default_output_extension = ".exe" 152 | default_output_dir = "{{root_out_dir}}" 153 | description = "LINK {{output}}" 154 | outputs = [ 155 | exename, 156 | pdbname, 157 | ] 158 | runtime_outputs = outputs 159 | 160 | # The use of inputs_newline is to work around a fixed per-line buffer 161 | # size in the linker. 162 | rspfile_content = "{{inputs_newline}} {{libs}} {{solibs}} {{rlibs}}" 163 | } 164 | 165 | # These two are really entirely generic, but have to be repeated in 166 | # each toolchain because GN doesn't allow a template to be used here. 167 | # See //build/toolchain/toolchain.gni for details. 168 | tool("stamp") { 169 | command = "cmd /c type nul > \"{{output}}\"" 170 | description = "STAMP {{output}}" 171 | } 172 | tool("copy") { 173 | command = "python $copy_script {{source}} {{output}}" 174 | description = "COPY {{source}} {{output}}" 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /tools/boost.gni: -------------------------------------------------------------------------------- 1 | template("boost") { 2 | # required: boost_source_dir, boost_outputs 3 | # optional: boost_libraries, boost_build_dir, boost_install_dir, boost_install_headers, boost_layout, boost_shared_library boost_defines 4 | action("$target_name") { 5 | boost_libraries = [] 6 | boost_build_dir = target_out_dir + "/" + target_name 7 | boost_install_dir = root_out_dir + "/" + target_name 8 | boost_install_headers = false 9 | boost_layout = "" 10 | boost_shared_library = false 11 | boost_defines = [] 12 | forward_variables_from(invoker, 13 | "*", 14 | [ 15 | "script", 16 | "args", 17 | "input", 18 | "output_name", 19 | ]) 20 | boost_env = "" 21 | if (is_win) { 22 | boost_env = "environment." + host_cpu + "." + target_cpu 23 | } 24 | if (is_winxp) { 25 | boost_defines += [ 26 | "BOOST_USE_WINAPI_VERSION=BOOST_WINAPI_VERSION_WINXP", 27 | "_WIN32_WINNT=BOOST_WINAPI_VERSION_WINXP", 28 | ] 29 | } 30 | toolset = "" 31 | if (is_winxp) { 32 | if (vs_version > 141) { 33 | toolset = 141 34 | } else if (vs_version >= 110) { 35 | toolset = vs_version 36 | } 37 | } 38 | script = "//build/tools/boost.py" 39 | args = [ 40 | rebase_path(boost_source_dir, root_build_dir), 41 | string_join(",", boost_libraries) + " ", 42 | rebase_path(boost_build_dir, root_build_dir), 43 | rebase_path(boost_install_dir, root_build_dir), 44 | "$boost_install_headers", 45 | target_cpu, 46 | "$is_debug", 47 | "$static_link_crt", 48 | boost_layout, 49 | "$boost_shared_library", 50 | string_join(",", boost_defines) + " ", 51 | boost_env + " ", 52 | toolset + " ", 53 | ] 54 | inputs = [ boost_source_dir ] 55 | outputs = boost_outputs 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /tools/boost.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | 7 | 8 | def build_boost( 9 | boost_source_dir, 10 | boost_libraries, 11 | build_dir, 12 | install_dir, 13 | install_headers, 14 | target_cpu, 15 | is_debug, 16 | static_link_crt, 17 | boost_layout, 18 | boost_shared_library, 19 | boost_defines, 20 | boost_env, 21 | toolset 22 | ): 23 | build_dir = os.path.abspath(build_dir) 24 | install_dir = os.path.abspath(install_dir) 25 | include_dir = '' if install_headers else '--includedir=.' 26 | 27 | if len(boost_env) > 0: 28 | with open(boost_env, 'r') as f: 29 | env = f.read() 30 | for e in env.split('\0'): 31 | kv = e.strip().split('=', 2) 32 | if len(kv) >= 2: 33 | os.environ[kv[0]] = kv[1] 34 | 35 | os.chdir(boost_source_dir) 36 | b2 = 'b2.exe' if sys.platform == 'win32' else './b2' 37 | if not os.path.exists(b2): 38 | if sys.platform == 'win32': 39 | os.system('bootstrap.bat') 40 | else: 41 | os.system('./bootstrap.sh') 42 | runtime_link = 'static' if sys.platform == 'win32' and static_link_crt else 'shared' 43 | address_model = 32 if target_cpu == 'x86' else 64 44 | variant = 'debug' if is_debug else 'release' 45 | libraries = '' 46 | if len(boost_libraries) > 0: 47 | libraries = ' '.join( 48 | map(lambda item: '--with-' + item, boost_libraries.split(','))) 49 | layout = '' 50 | link = 'shared' if boost_shared_library else 'static' 51 | if len(boost_layout) > 0: 52 | layout = '--layout=%s' % boost_layout 53 | 54 | if len(toolset) > 0: 55 | toolset = 'toolset=msvc-' + str(float(toolset) / 10) 56 | 57 | defines = '' 58 | if len(boost_defines) > 0: 59 | defines = ' '.join(map(lambda item: 'define=%s' % 60 | item, boost_defines.split(','))) 61 | 62 | action = 'install' if len(boost_libraries) > 0 else 'header' 63 | cflags = '' 64 | if sys.platform == 'linux': 65 | cflags = 'cflags=-fPIC cxxflags=-fPIC' 66 | cmd = '%s --build-dir=%s --prefix=%s %s address-model=%d %s %s variant=%s link=%s threading=multi runtime-link=%s %s %s %s %s' % ( 67 | b2, build_dir, install_dir, include_dir, address_model, layout, libraries, variant, link, runtime_link, toolset, cflags, defines, action) 68 | 69 | print(cmd) 70 | os.system(cmd) 71 | 72 | 73 | def main(): 74 | [ 75 | boost_source_dir, 76 | boost_libraries, 77 | build_dir, 78 | install_dir, 79 | install_headers, 80 | target_cpu, 81 | is_debug, 82 | static_link_crt, 83 | boost_layout, 84 | boost_shared_library, 85 | boost_defines, 86 | boost_env, 87 | toolset, 88 | ] = sys.argv[1:] 89 | 90 | build_boost( 91 | boost_source_dir, 92 | boost_libraries.strip(), 93 | build_dir, 94 | install_dir, 95 | install_headers == 'true', 96 | target_cpu, 97 | is_debug == 'true', 98 | static_link_crt == 'true', 99 | boost_layout, 100 | boost_shared_library == 'true', 101 | boost_defines.strip(), 102 | boost_env.strip(), 103 | toolset.strip(), 104 | ) 105 | 106 | 107 | if __name__ == '__main__': 108 | main() 109 | -------------------------------------------------------------------------------- /tools/cmake.gni: -------------------------------------------------------------------------------- 1 | template("cmake") { 2 | # required: cmake_root_dir, cmake_outputs 3 | # optional: cmake_options, cmake_build_dir, cmake_install_dir 4 | action("$target_name") { 5 | cmake_options = [] 6 | cmake_build_dir = target_out_dir + "/" + target_name 7 | cmake_install_dir = root_out_dir + "/" + target_name 8 | forward_variables_from(invoker, 9 | "*", 10 | [ 11 | "script", 12 | "args", 13 | "input", 14 | "output_name", 15 | ]) 16 | toolset = "" 17 | if (is_winxp) { 18 | if (vs_version > 141) { 19 | toolset = "v141_xp" 20 | } else if (vs_version >= 110) { 21 | toolset = "v${vs_version}_xp" 22 | } 23 | } 24 | script = "//build/tools/cmake.py" 25 | args = [ 26 | rebase_path(cmake_root_dir, root_build_dir), 27 | string_join(",", cmake_options) + " ", 28 | rebase_path(cmake_build_dir, root_build_dir), 29 | rebase_path(cmake_install_dir, root_build_dir), 30 | "$target_cpu", 31 | "$is_debug", 32 | "$static_link_crt", 33 | toolset + " ", 34 | winver + " ", 35 | ] 36 | inputs = [ cmake_root_dir ] 37 | outputs = cmake_outputs 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /tools/cmake.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | 7 | 8 | def cmake_build( 9 | cmake_root, 10 | cmake_options, 11 | build_dir, 12 | install_dir, 13 | target_cpu, 14 | is_debug, 15 | static_link_crt, 16 | toolset, 17 | winver, 18 | ): 19 | config = 'debug' if is_debug else 'release' 20 | options = '' 21 | cflags = '' 22 | cxxflags = '' 23 | if sys.platform == 'win32': 24 | options += '-A %s ' % ('Win32' if target_cpu == 'x86' else 'x64') 25 | crt_link_flags = 'MultiThreaded%s%s' % ( 26 | 'Debug' if is_debug else '', 27 | '' if static_link_crt else 'DLL', 28 | ) 29 | options += '-DCMAKE_POLICY_DEFAULT_CMP0091=NEW -DCMAKE_MSVC_RUNTIME_LIBRARY=%s ' % ( 30 | crt_link_flags,) 31 | elif sys.platform == 'darwin': 32 | options += '-DCMAKE_OSX_ARCHITECTURES=%s ' % 'i386' if target_cpu == 'x86' else 'x86_64' 33 | else: 34 | cflags = '-m32 ' if target_cpu == 'x86' else '-m64 ' 35 | cxxflags = '-m32 ' if target_cpu == 'x86' else '-m64 ' 36 | options += '-DCMAKE_INSTALL_PREFIX=%s ' % install_dir 37 | if len(cmake_options) > 0: 38 | options += ' '.join(map(lambda item: '-D' + item, 39 | cmake_options.split(','))) 40 | if len(winver) > 0: 41 | cflags += '/D_WIN32_WINNT=%s ' % winver 42 | cxxflags += '/D_WIN32_WINNT=%s ' % winver 43 | if len(cflags) > 0: 44 | options += ' -DCMAKE_C_FLAGS_INIT="%s"' % cflags 45 | if len(cxxflags) > 0: 46 | options += ' -DCMAKE_CXX_FLAGS_INIT="%s"' % cxxflags 47 | if len(toolset) > 0: 48 | options += ' -T %s' % toolset 49 | config_cmd = 'cmake %s -S %s -B %s' % ( 50 | options, 51 | cmake_root, 52 | build_dir, 53 | ) 54 | build_cmd = 'cmake --build %s --config %s' % (build_dir, config) 55 | install_cmd = 'cmake --install %s --config %s --prefix %s' % ( 56 | build_dir, 57 | config, 58 | install_dir, 59 | ) 60 | for cmd in (config_cmd, build_cmd, install_cmd): 61 | print(cmd) 62 | sys.stdout.flush() 63 | os.system(cmd) 64 | 65 | 66 | def main(): 67 | [ 68 | cmake_root, 69 | cmake_options, 70 | build_dir, 71 | install_dir, 72 | target_cpu, 73 | is_debug, 74 | static_link_crt, 75 | toolset, 76 | winver, 77 | ] = sys.argv[1:] 78 | 79 | cmake_build( 80 | cmake_root, 81 | cmake_options.strip(), 82 | build_dir, 83 | install_dir, 84 | target_cpu, 85 | is_debug == 'true', 86 | static_link_crt == 'true', 87 | toolset.strip(), 88 | winver.strip(), 89 | ) 90 | 91 | 92 | if __name__ == '__main__': 93 | main() 94 | -------------------------------------------------------------------------------- /tools/copy.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | 5 | import os 6 | import sys 7 | 8 | def main(): 9 | if sys.platform == 'win32': 10 | os.system("copy /Y %s %s" % (sys.argv[1].replace('/', os.path.sep), sys.argv[2].replace('/', os.path.sep))) 11 | else: 12 | os.system("cp -r %s %s" % (sys.argv[1], sys.argv[2])) 13 | 14 | if __name__ == '__main__': 15 | main() 16 | -------------------------------------------------------------------------------- /tools/gn.gni: -------------------------------------------------------------------------------- 1 | template("gn") { 2 | # required: gn_root_dir 3 | # optional: gn_targets, gn_args, export_include_dirs, export_defines, export_libs, depended_libs, output_files 4 | 5 | config("${target_name}_public_config") { 6 | lib_dirs = [ target_out_dir + "/" + target_name ] 7 | if (defined(invoker.export_include_dirs)) { 8 | include_dirs = invoker.export_include_dirs 9 | } 10 | if (defined(invoker.export_defines)) { 11 | defines = invoker.export_defines 12 | } 13 | libs = [] 14 | if (defined(invoker.export_libs)) { 15 | libs += invoker.export_libs 16 | } 17 | if (defined(invoker.depend_libs)) { 18 | libs += invoker.depend_libs 19 | } 20 | } 21 | 22 | action("$target_name") { 23 | forward_variables_from(invoker, 24 | "*", 25 | [ 26 | "script", 27 | "args", 28 | "input", 29 | "public_configs", 30 | ]) 31 | if (!defined(gn_targets)) { 32 | gn_targets = [] 33 | } 34 | if (!defined(gn_args)) { 35 | gn_args = [] 36 | } 37 | gn_args += [ 38 | "host_cpu=\"$host_cpu\"", 39 | "host_os=\"$host_os\"", 40 | "current_cpu=\"$current_cpu\"", 41 | "current_os=\"$current_os\"", 42 | "target_cpu=\"$target_cpu\"", 43 | "target_os=\"$target_os\"", 44 | "is_debug=$is_debug", 45 | "is_winxp=$is_winxp", 46 | "static_link_crt=$static_link_crt", 47 | "winver=\"$winver\"", 48 | ] 49 | script = "//build/tools/gn.py" 50 | args = [ 51 | rebase_path(gn_root_dir, root_build_dir), 52 | rebase_path(target_name, root_build_dir, target_out_dir), 53 | string_join(" ", gn_targets) + " ", 54 | string_join(" ", gn_args) + " ", 55 | ] 56 | inputs = [ gn_root_dir ] 57 | outputs = [] 58 | if (defined(export_libs)) { 59 | foreach(lib, export_libs) { 60 | outputs += [ "$target_out_dir/$lib" ] 61 | } 62 | } 63 | if (defined(output_files)) { 64 | foreach(file, output_files) { 65 | outputs += [ "$target_out_dir/$file" ] 66 | } 67 | } 68 | public_configs = [ ":${target_name}_public_config" ] 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /tools/gn.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | 7 | 8 | def gn_build( 9 | root_dir, 10 | out_dir, 11 | targets, 12 | args 13 | ): 14 | gen_cmd = 'gn gen --root=%s %s --args="%s"' % ( 15 | root_dir, 16 | out_dir, 17 | args.replace('"', '\\"') 18 | ) 19 | build_cmd = 'ninja -C %s %s' % (out_dir, targets) 20 | for cmd in (gen_cmd, build_cmd): 21 | print(cmd) 22 | sys.stdout.flush() 23 | r = os.system(cmd) 24 | assert r == 0 25 | 26 | 27 | def main(): 28 | [ 29 | root_dir, 30 | out_dir, 31 | targets, 32 | args, 33 | ] = sys.argv[1:] 34 | 35 | gn_build( 36 | root_dir, 37 | out_dir, 38 | targets.strip(), 39 | args.strip() 40 | ) 41 | 42 | 43 | if __name__ == '__main__': 44 | main() 45 | -------------------------------------------------------------------------------- /tools/golang.gni: -------------------------------------------------------------------------------- 1 | template("golang") { 2 | # required: go_root_dir, go_outputs 3 | # optional: go_gcflags, go_ldflags, go_out_dir 4 | action("$target_name") { 5 | go_gcflags = [] 6 | go_ldflags = [] 7 | go_out_dir = root_out_dir 8 | forward_variables_from(invoker, 9 | "*", 10 | [ 11 | "script", 12 | "args", 13 | "output_name", 14 | ]) 15 | script = "//build/tools/golang.py" 16 | args = [ 17 | rebase_path(go_root_dir, root_build_dir), 18 | rebase_path(go_out_dir, root_build_dir), 19 | string_join(",", go_gcflags) + " ", 20 | string_join(",", go_ldflags) + " ", 21 | "$is_debug", 22 | ] 23 | outputs = go_outputs 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /tools/golang.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | 7 | 8 | def golang_build(go_root_dir, go_out_dir, go_gcflags, go_ldflags, is_debug): 9 | out_dir = os.path.abspath(go_out_dir) 10 | gcflags_list = [] 11 | if len(go_gcflags) > 0: 12 | gcflags_list = go_gcflags.split(',') 13 | if is_debug: 14 | gcflags_list = gcflags_list + ['-N', '-l'] 15 | gcflags = ' '.join(gcflags_list) 16 | if len(gcflags) > 0: 17 | gcflags = ' -gcflags "%s"' % gcflags 18 | 19 | ldlags_list = [] 20 | if len(go_ldflags) > 0: 21 | ldlags_list = go_ldflags.split(',') 22 | if not is_debug: 23 | ldlags_list = ldlags_list + ['-w', '-s'] 24 | ldflags = ' '.join(ldlags_list) 25 | if len(ldflags) > 0: 26 | ldflags = ' -ldflags "%s"' % ldflags 27 | 28 | os.chdir(go_root_dir) 29 | 30 | cmd = 'go build%s%s -o %s' % (gcflags, ldflags, out_dir) 31 | print(cmd) 32 | os.system(cmd) 33 | 34 | 35 | def main(): 36 | [ 37 | go_root_dir, 38 | go_out_dir, 39 | go_gcflags, 40 | go_ldflags, 41 | is_debug, 42 | ] = sys.argv[1:] 43 | 44 | golang_build( 45 | go_root_dir, 46 | go_out_dir, 47 | go_gcflags.strip(), 48 | go_ldflags.strip(), 49 | is_debug == 'true', 50 | ) 51 | 52 | 53 | if __name__ == '__main__': 54 | main() 55 | -------------------------------------------------------------------------------- /tools/makefile.gni: -------------------------------------------------------------------------------- 1 | template("makefile") { 2 | # required: makefile_root_dir, makefile_outputs 3 | # optional: makefile_config_cmd, makefile_prefix, makefile_file, makefile_options, makefile_target 4 | action("$target_name") { 5 | makefile_config_cmd = "./configure" 6 | makefile_prefix = root_out_dir + "/" + target_name 7 | makefile_config_options = [] 8 | makefile_file = "" 9 | makefile_options = [] 10 | makefile_targets = [ 11 | "", 12 | "install", 13 | ] 14 | forward_variables_from(invoker, 15 | "*", 16 | [ 17 | "script", 18 | "args", 19 | "input", 20 | "output_name", 21 | ]) 22 | makefile_env = "" 23 | if (is_win) { 24 | makefile_env = "environment." + host_cpu + "." + target_cpu 25 | } 26 | script = "//build/tools/makefile.py" 27 | args = [ 28 | rebase_path(makefile_root_dir, root_build_dir), 29 | "$makefile_config_cmd ", 30 | rebase_path(makefile_prefix, root_build_dir), 31 | string_join(",", makefile_config_options) + " ", 32 | makefile_file + " ", 33 | string_join(",", makefile_options) + " ", 34 | string_join(",", makefile_targets) + " ", 35 | makefile_env + " ", 36 | ] 37 | inputs = [ makefile_root_dir ] 38 | outputs = makefile_outputs 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /tools/makefile.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | 7 | 8 | def makefile_build( 9 | makefile_root_dir, 10 | makefile_config_cmd, 11 | makefile_prefix, 12 | makefile_config_options, 13 | makefile_file, 14 | makefile_options, 15 | makefile_targets, 16 | makefile_env, 17 | ): 18 | prefix = os.path.abspath(makefile_prefix) 19 | config_options = '' 20 | if len(makefile_config_options) > 0: 21 | config_options = ' '.join( 22 | map(lambda item: item, makefile_config_options.split(','))) 23 | options = '' 24 | if len(makefile_options) > 0: 25 | options = ' '.join(map(lambda item: item, makefile_options.split(','))) 26 | targets = [] 27 | if len(makefile_targets) > 0: 28 | targets = makefile_targets.split(',') 29 | else: 30 | targets = [''] 31 | 32 | if len(makefile_env) > 0: 33 | with open(makefile_env, 'r') as f: 34 | env = f.read() 35 | for e in env.split('\0'): 36 | kv = e.strip().split('=', 2) 37 | if len(kv) >= 2: 38 | os.environ[kv[0]] = kv[1] 39 | 40 | os.chdir(makefile_root_dir) 41 | if len(makefile_config_cmd) > 0: 42 | config_cmd = '%s --prefix=%s %s' % ( 43 | makefile_config_cmd, 44 | prefix, 45 | config_options, 46 | ) 47 | print(config_cmd) 48 | sys.stdout.flush() 49 | os.system(config_cmd) 50 | os.system('echo > "%s"' % os.path.join(prefix, 'configure')) 51 | 52 | make = 'make' if sys.platform != 'win32' else 'nmake' 53 | if sys.platform == 'win32' and len(makefile_file) > 0: 54 | make += " /f %s" % makefile_file 55 | for target in targets: 56 | make_cmd = '%s %s %s' % (make, target, options) 57 | print(make_cmd) 58 | sys.stdout.flush() 59 | os.system(make_cmd) 60 | os.system('echo > "%s"' % os.path.join(prefix, 'make' 61 | + ('' if len(target) == 0 else '_' + target.replace('/', '_').replace('\\', '_').replace('.', '_')))) 62 | 63 | 64 | def main(): 65 | [ 66 | makefile_root_dir, 67 | makefile_config_cmd, 68 | makefile_prefix, 69 | makefile_config_options, 70 | makefile_file, 71 | makefile_options, 72 | makefile_targets, 73 | makefile_env, 74 | ] = sys.argv[1:] 75 | 76 | makefile_build( 77 | makefile_root_dir, 78 | makefile_config_cmd.strip(), 79 | makefile_prefix, 80 | makefile_config_options, 81 | makefile_file.strip(), 82 | makefile_options.strip(), 83 | makefile_targets.strip(), 84 | makefile_env.strip(), 85 | ) 86 | 87 | 88 | if __name__ == '__main__': 89 | main() 90 | --------------------------------------------------------------------------------