summaryrefslogtreecommitdiff
path: root/CMakeLists.txt
blob: ac62a490b31de4466f09af12b498a3fca5685b53 (plain)
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
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
find_program(RE2C re2c)
if(RE2C)
	# 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 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)
  # 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)
  endif()
  target_link_libraries(ninja_test PRIVATE libninja libninja-re2c)

  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()