1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
|
cmake_minimum_required(VERSION 3.15)
include(CheckSymbolExists)
include(CheckIPOSupported)
option(NINJA_BUILD_BINARY "Build ninja binary" ON)
option(NINJA_FORCE_PSELECT "Use pselect() even on platforms that provide ppoll()" OFF)
project(ninja CXX)
# --- optional link-time optimization
check_ipo_supported(RESULT lto_supported OUTPUT error)
if(lto_supported)
message(STATUS "IPO / LTO enabled")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
else()
message(STATUS "IPO / LTO not supported: <${error}>")
endif()
# --- compiler flags
if(MSVC)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
string(REPLACE "/GR" "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
# Note that these settings are separately specified in configure.py, and
# these lists should be kept in sync.
add_compile_options(/W4 /wd4100 /wd4267 /wd4706 /wd4702 /wd4244 /GR- /Zc:__cplusplus)
add_compile_definitions(_CRT_SECURE_NO_WARNINGS)
else()
include(CheckCXXCompilerFlag)
check_cxx_compiler_flag(-Wno-deprecated flag_no_deprecated)
if(flag_no_deprecated)
add_compile_options(-Wno-deprecated)
endif()
check_cxx_compiler_flag(-fdiagnostics-color flag_color_diag)
if(flag_color_diag)
add_compile_options(-fdiagnostics-color)
endif()
if(NOT NINJA_FORCE_PSELECT)
# Check whether ppoll() is usable on the target platform.
# Set -DUSE_PPOLL=1 if this is the case.
#
# NOTE: Use check_cxx_symbol_exists() instead of check_symbol_exists()
# because on Linux, <poll.h> only exposes the symbol when _GNU_SOURCE
# is defined.
#
# Both g++ and clang++ define the symbol by default, because the C++
# standard library headers require it, but *not* gcc and clang, which
# are used by check_symbol_exists().
include(CheckCXXSymbolExists)
check_cxx_symbol_exists(ppoll poll.h HAVE_PPOLL)
if(HAVE_PPOLL)
add_compile_definitions(USE_PPOLL=1)
endif()
endif()
endif()
# --- optional re2c
set(RE2C_MAJOR_VERSION 0)
find_program(RE2C re2c)
if(RE2C)
execute_process(COMMAND "${RE2C}" --vernum OUTPUT_VARIABLE RE2C_RAW_VERSION)
math(EXPR RE2C_MAJOR_VERSION "${RE2C_RAW_VERSION} / 10000")
endif()
if(${RE2C_MAJOR_VERSION} GREATER 1)
# the depfile parser and ninja lexers are generated using re2c.
function(re2c IN OUT)
add_custom_command(DEPENDS ${IN} OUTPUT ${OUT}
COMMAND ${RE2C} -b -i --no-generation-date --no-version -o ${OUT} ${IN}
)
endfunction()
re2c(${PROJECT_SOURCE_DIR}/src/depfile_parser.in.cc ${PROJECT_BINARY_DIR}/depfile_parser.cc)
re2c(${PROJECT_SOURCE_DIR}/src/lexer.in.cc ${PROJECT_BINARY_DIR}/lexer.cc)
add_library(libninja-re2c OBJECT ${PROJECT_BINARY_DIR}/depfile_parser.cc ${PROJECT_BINARY_DIR}/lexer.cc)
else()
message(WARNING "re2c 2 or later was not found; changes to src/*.in.cc will not affect your build.")
add_library(libninja-re2c OBJECT src/depfile_parser.cc src/lexer.cc)
endif()
target_include_directories(libninja-re2c PRIVATE src)
# --- Check for 'browse' mode support
function(check_platform_supports_browse_mode RESULT)
# Make sure the inline.sh script works on this platform.
# It uses the shell commands such as 'od', which may not be available.
execute_process(
COMMAND sh -c "echo 'TEST' | src/inline.sh var"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE inline_result
OUTPUT_QUIET
ERROR_QUIET
)
if(NOT inline_result EQUAL "0")
# The inline script failed, so browse mode is not supported.
set(${RESULT} "0" PARENT_SCOPE)
if(NOT WIN32)
message(WARNING "browse feature omitted due to inline script failure")
endif()
return()
endif()
# Now check availability of the unistd header
check_symbol_exists(fork "unistd.h" HAVE_FORK)
check_symbol_exists(pipe "unistd.h" HAVE_PIPE)
set(browse_supported 0)
if (HAVE_FORK AND HAVE_PIPE)
set(browse_supported 1)
endif ()
set(${RESULT} "${browse_supported}" PARENT_SCOPE)
if(NOT browse_supported)
message(WARNING "browse feature omitted due to missing `fork` and `pipe` functions")
endif()
endfunction()
set(NINJA_PYTHON "python" CACHE STRING "Python interpreter to use for the browse tool")
check_platform_supports_browse_mode(platform_supports_ninja_browse)
# Core source files all build into ninja library.
add_library(libninja OBJECT
src/build_log.cc
src/build.cc
src/clean.cc
src/clparser.cc
src/dyndep.cc
src/dyndep_parser.cc
src/debug_flags.cc
src/deps_log.cc
src/disk_interface.cc
src/edit_distance.cc
src/eval_env.cc
src/graph.cc
src/graphviz.cc
src/json.cc
src/line_printer.cc
src/manifest_parser.cc
src/metrics.cc
src/missing_deps.cc
src/parser.cc
src/state.cc
src/status.cc
src/string_piece_util.cc
src/util.cc
src/version.cc
)
if(WIN32)
target_sources(libninja PRIVATE
src/subprocess-win32.cc
src/includes_normalize-win32.cc
src/msvc_helper-win32.cc
src/msvc_helper_main-win32.cc
src/getopt.c
src/minidump-win32.cc
)
# Build getopt.c, which can be compiled as either C or C++, as C++
# so that build environments which lack a C compiler, but have a C++
# compiler may build ninja.
set_source_files_properties(src/getopt.c PROPERTIES LANGUAGE CXX)
else()
target_sources(libninja PRIVATE src/subprocess-posix.cc)
if(CMAKE_SYSTEM_NAME STREQUAL "OS400" OR CMAKE_SYSTEM_NAME STREQUAL "AIX")
target_sources(libninja PRIVATE src/getopt.c)
# Build getopt.c, which can be compiled as either C or C++, as C++
# so that build environments which lack a C compiler, but have a C++
# compiler may build ninja.
set_source_files_properties(src/getopt.c PROPERTIES LANGUAGE CXX)
endif()
# Needed for perfstat_cpu_total
if(CMAKE_SYSTEM_NAME STREQUAL "AIX")
target_link_libraries(libninja PUBLIC "-lperfstat")
endif()
endif()
target_compile_features(libninja PUBLIC cxx_std_11)
#Fixes GetActiveProcessorCount on MinGW
if(MINGW)
target_compile_definitions(libninja PRIVATE _WIN32_WINNT=0x0601 __USE_MINGW_ANSI_STDIO=1)
endif()
# On IBM i (identified as "OS400" for compatibility reasons) and AIX, this fixes missing
# PRId64 (and others) at compile time in C++ sources
if(CMAKE_SYSTEM_NAME STREQUAL "OS400" OR CMAKE_SYSTEM_NAME STREQUAL "AIX")
add_compile_definitions(__STDC_FORMAT_MACROS)
endif()
# Main executable is library plus main() function.
if(NINJA_BUILD_BINARY)
add_executable(ninja src/ninja.cc)
target_link_libraries(ninja PRIVATE libninja libninja-re2c)
if(WIN32)
target_sources(ninja PRIVATE windows/ninja.manifest)
endif()
endif()
# Adds browse mode into the ninja binary if it's supported by the host platform.
if(platform_supports_ninja_browse)
# Inlines src/browse.py into the browse_py.h header, so that it can be included
# by src/browse.cc
add_custom_command(
OUTPUT build/browse_py.h
MAIN_DEPENDENCY src/browse.py
DEPENDS src/inline.sh
COMMAND ${CMAKE_COMMAND} -E make_directory ${PROJECT_BINARY_DIR}/build
COMMAND src/inline.sh kBrowsePy
< src/browse.py
> ${PROJECT_BINARY_DIR}/build/browse_py.h
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
VERBATIM
)
if(NINJA_BUILD_BINARY)
target_compile_definitions(ninja PRIVATE NINJA_HAVE_BROWSE)
target_sources(ninja PRIVATE src/browse.cc)
endif()
set_source_files_properties(src/browse.cc
PROPERTIES
OBJECT_DEPENDS "${PROJECT_BINARY_DIR}/build/browse_py.h"
INCLUDE_DIRECTORIES "${PROJECT_BINARY_DIR}"
COMPILE_DEFINITIONS NINJA_PYTHON="${NINJA_PYTHON}"
)
endif()
include(CTest)
if(BUILD_TESTING)
find_package(GTest)
if(NOT GTest_FOUND)
include(FetchContent)
FetchContent_Declare(
googletest
URL https://github.com/google/googletest/archive/release-1.10.0.tar.gz
URL_HASH SHA1=9c89be7df9c5e8cb0bc20b3c4b39bf7e82686770
)
FetchContent_MakeAvailable(googletest)
# Before googletest-1.11.0, the CMake files provided by the source archive
# did not define the GTest::gtest target, only the gtest one, so define
# an alias when needed to ensure the rest of this file works with all
# GoogleTest releases.
#
# Note that surprisingly, this is not needed when using GTEST_ROOT to
# point to a local installation, because this one contains CMake-generated
# files that contain the right target definition, and which will be
# picked up by the find_package(GTest) file above.
#
# This comment and the four lines below can be removed once Ninja only
# depends on release-1.11.0 or above.
if (NOT TARGET GTest::gtest)
message(STATUS "Defining GTest::gtest alias to work-around bug in older release.")
add_library(GTest::gtest ALIAS gtest)
# NOTE: gtest uninit some variables, gcc >= 1.11.3 may cause error on compile.
# Remove this comment and six lines below, once ninja deps gtest-1.11.0 or above.
if (CMAKE_COMPILER_IS_GNUCXX AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER "1.11.3")
check_cxx_compiler_flag(-Wno-maybe-uninitialized flag_no_maybe_uninit)
if (flag_no_maybe_uninit)
target_compile_options(gtest PRIVATE -Wno-maybe-uninitialized)
endif()
endif()
endif()
endif()
# Tests all build into ninja_test executable.
add_executable(ninja_test
src/build_log_test.cc
src/build_test.cc
src/clean_test.cc
src/clparser_test.cc
src/depfile_parser_test.cc
src/deps_log_test.cc
src/disk_interface_test.cc
src/dyndep_parser_test.cc
src/edit_distance_test.cc
src/graph_test.cc
src/json_test.cc
src/lexer_test.cc
src/manifest_parser_test.cc
src/missing_deps_test.cc
src/ninja_test.cc
src/state_test.cc
src/string_piece_util_test.cc
src/subprocess_test.cc
src/test.cc
src/util_test.cc
)
if(WIN32)
target_sources(ninja_test PRIVATE src/includes_normalize_test.cc src/msvc_helper_test.cc
windows/ninja.manifest)
endif()
find_package(Threads REQUIRED)
target_link_libraries(ninja_test PRIVATE libninja libninja-re2c GTest::gtest Threads::Threads)
foreach(perftest
build_log_perftest
canon_perftest
clparser_perftest
depfile_parser_perftest
hash_collision_bench
manifest_parser_perftest
)
add_executable(${perftest} src/${perftest}.cc)
target_link_libraries(${perftest} PRIVATE libninja libninja-re2c)
endforeach()
if(CMAKE_SYSTEM_NAME STREQUAL "AIX" AND CMAKE_SIZEOF_VOID_P EQUAL 4)
# These tests require more memory than will fit in the standard AIX shared stack/heap (256M)
target_link_options(hash_collision_bench PRIVATE "-Wl,-bmaxdata:0x80000000")
target_link_options(manifest_parser_perftest PRIVATE "-Wl,-bmaxdata:0x80000000")
endif()
add_test(NAME NinjaTest COMMAND ninja_test)
endif()
if(NINJA_BUILD_BINARY)
install(TARGETS ninja)
endif()
|