Codechange: A vehicle that is not a front engine can't be removed from a vehicle...
[openttd-github.git] / CMakeLists.txt
blob27b7b0e7d21200786e9c75d7f60e2bcd3c45a4b7
1 cmake_minimum_required(VERSION 3.16)
3 if(NOT BINARY_NAME)
4     set(BINARY_NAME openttd)
5 endif()
7 project(${BINARY_NAME}
8     VERSION 14.0
9     LANGUAGES CXX
12 if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR)
13     message(FATAL_ERROR "In-source builds not allowed. Please run \"cmake ..\" from the build directory. You may need to delete \"${CMAKE_SOURCE_DIR}/CMakeCache.txt\" first.")
14 endif()
16 # Debug mode by default.
17 if(NOT CMAKE_BUILD_TYPE)
18     set(CMAKE_BUILD_TYPE Debug)
19 endif()
21 if (EMSCRIPTEN)
22     set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/os/emscripten/cmake")
23 endif()
25 set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
26 set(CMAKE_OSX_DEPLOYMENT_TARGET 10.13)
28 # Use GNUInstallDirs to allow customisation
29 # but set our own default data and bin dir
30 if(NOT CMAKE_INSTALL_DATADIR)
31     set(CMAKE_INSTALL_DATADIR "share/games")
32 endif()
33 if(NOT CMAKE_INSTALL_BINDIR)
34     set(CMAKE_INSTALL_BINDIR "games")
35 endif()
36 include(GNUInstallDirs)
38 include(Options)
39 set_options()
40 set_directory_options()
42 include(Static)
43 set_static_if_needed()
45 set(CMAKE_CXX_STANDARD 17)
46 set(CMAKE_CXX_STANDARD_REQUIRED YES)
47 set(CMAKE_CXX_EXTENSIONS NO)
49 set(CMAKE_EXPORT_COMPILE_COMMANDS YES)
51 # An empty target for the tools
52 add_custom_target(tools)
54 include(Endian)
55 add_endian_definition()
57 include(CompileFlags)
58 compile_flags()
60 if(APPLE OR UNIX)
61     add_definitions(-DUNIX)
62 endif()
64 if(UNIX)
65     find_package(Doxygen)
66 endif()
68 list(APPEND GENERATED_SOURCE_FILES "${CMAKE_BINARY_DIR}/generated/rev.cpp")
69 if(WIN32)
70     list(APPEND GENERATED_SOURCE_FILES "${CMAKE_BINARY_DIR}/generated/ottdres.rc")
71 endif()
73 # Generate a target to determine version, which is execute every 'make' run
74 add_custom_target(find_version
75         ${CMAKE_COMMAND}
76                 -DFIND_VERSION_BINARY_DIR=${CMAKE_BINARY_DIR}/generated
77                 -DCPACK_BINARY_DIR=${CMAKE_BINARY_DIR}
78                 -DREV_MAJOR=${PROJECT_VERSION_MAJOR}
79                 -DREV_MINOR=${PROJECT_VERSION_MINOR}
80                 -DWINDOWS=${WIN32}
81                 -P "${CMAKE_SOURCE_DIR}/cmake/scripts/FindVersion.cmake"
82         WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
83         BYPRODUCTS ${GENERATED_SOURCE_FILES}
86 # Documentation
87 if(DOXYGEN_EXECUTABLE)
88     add_custom_target(docs)
89     add_custom_target(docs_source
90         ${CMAKE_COMMAND} -E make_directory ${CMAKE_BINARY_DIR}/docs
91         COMMAND ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile
92         WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}
93         COMMENT "Generating documentation for source"
94     )
95     add_dependencies(docs_source
96         find_version
97     )
98     add_dependencies(docs
99         docs_source
100     )
101 endif()
103 include(AddCustomXXXTimestamp)
105 if(OPTION_TOOLS_ONLY)
106     if(HOST_BINARY_DIR)
107         unset(HOST_BINARY_DIR CACHE)
108     endif()
109     add_subdirectory(${CMAKE_SOURCE_DIR}/src)
110     return()
111 endif()
113 if(APPLE)
114         # Avoid searching for headers in Frameworks, and libraries in LIBDIR.
115         set(CMAKE_FIND_FRAMEWORK LAST)
116 endif()
118 # Prefer -pthread over -lpthread, which is often the better option of the two.
119 set(CMAKE_THREAD_PREFER_PTHREAD YES)
120 # Make sure we have Threads available.
121 find_package(Threads REQUIRED)
123 find_package(ZLIB)
124 find_package(LibLZMA)
125 find_package(LZO)
126 find_package(PNG)
128 if(WIN32 OR EMSCRIPTEN)
129     # Windows uses WinHttp for HTTP requests.
130     # Emscripten uses Javascript for HTTP requests.
131 else()
132     # All other targets use libcurl.
133     find_package(CURL)
134 endif()
136 if(NOT OPTION_DEDICATED)
137     if(NOT WIN32)
138         find_package(Allegro)
139         if(NOT APPLE)
140             find_package(Freetype)
141             find_package(SDL2)
142             if(NOT SDL2_FOUND)
143                 find_package(SDL)
144             endif()
145             find_package(Fluidsynth)
146             find_package(Fontconfig)
147             find_package(Harfbuzz)
148             find_package(ICU OPTIONAL_COMPONENTS i18n)
149         endif()
150     endif()
151 endif()
152 if(APPLE)
153     enable_language(OBJCXX)
155     find_package(Iconv)
157     find_library(AUDIOTOOLBOX_LIBRARY AudioToolbox)
158     find_library(AUDIOUNIT_LIBRARY AudioUnit)
159     find_library(COCOA_LIBRARY Cocoa)
160     find_library(QUARTZCORE_LIBRARY QuartzCore)
161 endif()
163 if(NOT EMSCRIPTEN AND NOT OPTION_DEDICATED)
164     find_package(OpenGL COMPONENTS OpenGL)
165 endif()
167 if(MSVC)
168     find_package(Editbin REQUIRED)
169 endif()
171 find_package(SSE)
172 find_package(Xaudio2)
174 find_package(Grfcodec)
176 include(CheckIPOSupported)
177 check_ipo_supported(RESULT IPO_FOUND)
179 show_options()
181 if(UNIX AND NOT APPLE AND NOT OPTION_DEDICATED)
182     if(NOT SDL_FOUND AND NOT SDL2_FOUND AND NOT ALLEGRO_FOUND)
183         message(FATAL_ERROR "SDL, SDL2 or Allegro is required for this platform")
184     endif()
185     if(HARFBUZZ_FOUND AND NOT ICU_i18n_FOUND)
186         message(WARNING "HarfBuzz depends on ICU i18n to function; HarfBuzz will be disabled")
187     endif()
188     if(NOT HARFBUZZ_FOUND)
189         message(WARNING "Without HarfBuzz and ICU i18n the game will not be able to render right-to-left languages correctly")
190     endif()
191 endif()
192 if(APPLE)
193     if(NOT AUDIOTOOLBOX_LIBRARY)
194         message(FATAL_ERROR "AudioToolbox is required for this platform")
195     endif()
196     if(NOT AUDIOUNIT_LIBRARY)
197         message(FATAL_ERROR "AudioUnit is required for this platform")
198     endif()
199     if(NOT COCOA_LIBRARY)
200         message(FATAL_ERROR "Cocoa is required for this platform")
201     endif()
202     if(NOT QUARTZCORE_LIBRARY)
203         message(FATAL_ERROR "QuartzCore is required for this platform")
204     endif()
205 endif()
207 if(OPTION_PACKAGE_DEPENDENCIES)
208     if(NOT UNIX)
209         message(FATAL_ERROR "Can only package dependencies on Linux")
210     endif()
211     if(OPTION_INSTALL_FHS)
212         message(FATAL_ERROR "Cannot install in FHS folders when we are packaging dependencies")
213     endif()
214     if(${CMAKE_VERSION} VERSION_LESS "3.16.0")
215         message(FATAL_ERROR "OPTION_PACKAGE_DEPENDENCIES can only work with CMake 3.16+; you are using ${CMAKE_VERSION}")
216     endif()
218     # If we are packaging dependencies, we do two things:
219     # 1) set the RPATH to include $ORIGIN/lib; $ORIGIN (that literal string)
220     #    is a Linux indicator for "path where application is". In CMake, we
221     #    have to do this before add_executable() is executed.
222     # 2) copy the libraries that we compile against to the "lib" folder.
223     #    This is done in InstallAndPackage.cmake.
224     set(CMAKE_INSTALL_RPATH "\$ORIGIN/lib")
225     set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
226 endif()
228 include(CTest)
229 include(SourceList)
231 # Needed by rev.cpp
232 include_directories(${CMAKE_SOURCE_DIR}/src)
233 # Needed by everything that uses Squirrel
234 include_directories(${CMAKE_SOURCE_DIR}/src/3rdparty/squirrel/include)
236 include(MSVCFilters)
238 add_library(openttd_lib OBJECT ${GENERATED_SOURCE_FILES})
239 add_executable(openttd WIN32)
240 add_executable(openttd_test)
241 set_target_properties(openttd PROPERTIES OUTPUT_NAME "${BINARY_NAME}")
242 # All other files are added via target_sources()
244 if(MSVC)
245     # Add DPI manifest to project; other WIN32 targets get this via ottdres.rc
246     target_sources(openttd PRIVATE "${CMAKE_SOURCE_DIR}/os/windows/openttd.manifest")
247 endif()
249 target_precompile_headers(openttd_lib
250     PRIVATE
251     src/stdafx.h
252     src/3rdparty/fmt/format.h
255 add_subdirectory(${CMAKE_SOURCE_DIR}/bin)
256 add_subdirectory(${CMAKE_SOURCE_DIR}/src)
257 add_subdirectory(${CMAKE_SOURCE_DIR}/media)
259 add_dependencies(openttd
260     find_version)
262 target_link_libraries(openttd_lib
263     openttd::languages
264     openttd::settings
265     openttd::script_api
266     Threads::Threads
269 target_link_libraries(openttd
270     openttd_lib
271     openttd::media
272     openttd::basesets
275 target_link_libraries(openttd_test PRIVATE openttd_lib)
276 include(Catch)
277 catch_discover_tests(openttd_test)
279 if(HAIKU)
280     target_link_libraries(openttd_lib "be" "network" "midi")
281 endif()
283 if(IPO_FOUND)
284     set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE True)
285     set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL True)
286     set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO True)
287 endif()
288 set_target_properties(openttd PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_BINARY_DIR}")
289 process_compile_flags()
291 include(LinkPackage)
292 link_package(PNG TARGET PNG::PNG ENCOURAGED)
293 link_package(ZLIB TARGET ZLIB::ZLIB ENCOURAGED)
294 link_package(LIBLZMA TARGET LibLZMA::LibLZMA ENCOURAGED)
295 link_package(LZO)
297 if(NOT WIN32 AND NOT EMSCRIPTEN)
298     link_package(CURL ENCOURAGED)
299 endif()
301 if(NOT OPTION_DEDICATED)
302     link_package(Fluidsynth)
303     link_package(SDL)
304     link_package(SDL2 TARGET SDL2::SDL2)
305     link_package(Allegro)
306     link_package(FREETYPE TARGET Freetype::Freetype)
307     link_package(Fontconfig TARGET Fontconfig::Fontconfig)
308     link_package(Harfbuzz TARGET harfbuzz::harfbuzz)
309     link_package(ICU_i18n)
311     if(SDL2_FOUND AND OPENGL_FOUND AND UNIX)
312         # SDL2 dynamically loads OpenGL if needed, so do not link to OpenGL when
313         # on Linux. For Windows, we need to link to OpenGL as we also have a win32
314         # driver using it.
315         add_definitions(-DWITH_OPENGL)
316         message(STATUS "OpenGL found -- -DWITH_OPENGL -- (via SDL2)")
317     else()
318         link_package(OpenGL TARGET OpenGL::GL)
319     endif()
320 endif()
322 include(CheckAtomic)
324 if(APPLE)
325     link_package(Iconv TARGET Iconv::Iconv)
327     target_link_libraries(openttd_lib
328         ${AUDIOTOOLBOX_LIBRARY}
329         ${AUDIOUNIT_LIBRARY}
330         ${COCOA_LIBRARY}
331         ${QUARTZCORE_LIBRARY}
332     )
334     add_definitions(
335         -DWITH_COCOA
336     )
337 endif()
339 if(EMSCRIPTEN)
340     add_library(WASM::WASM INTERFACE IMPORTED)
342     # Allow heap-growth, and start with a bigger memory size.
343     target_link_libraries(WASM::WASM INTERFACE "-s ALLOW_MEMORY_GROWTH=1")
344     target_link_libraries(WASM::WASM INTERFACE "-s INITIAL_MEMORY=33554432")
345     target_link_libraries(WASM::WASM INTERFACE "-s DISABLE_EXCEPTION_CATCHING=0")
346     add_definitions(-s DISABLE_EXCEPTION_CATCHING=0)
348     # Export functions to Javascript.
349     target_link_libraries(WASM::WASM INTERFACE "-s EXPORTED_FUNCTIONS='[\"_main\", \"_em_openttd_add_server\"]' -s EXPORTED_RUNTIME_METHODS='[\"cwrap\"]'")
351     # Preload all the files we generate during build.
352     # As we do not compile with FreeType / FontConfig, we also have no way to
353     # render several languages (like Chinese, ..), so where do you draw the
354     # line what languages to include and which not? In the end, especially as
355     # the more languages you add the slower downloading becomes, we decided to
356     # only ship the English language.
357     target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_BINARY_DIR}/baseset@/baseset")
358     target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_BINARY_DIR}/lang/english.lng@/lang/english.lng")
359     target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_SOURCE_DIR}/bin/ai@/ai")
360     target_link_libraries(WASM::WASM INTERFACE "--preload-file ${CMAKE_SOURCE_DIR}/bin/game@/game")
362     # We use IDBFS for persistent storage.
363     target_link_libraries(WASM::WASM INTERFACE "-lidbfs.js")
365     # Use custom pre-js and shell.html.
366     target_link_libraries(WASM::WASM INTERFACE "--pre-js ${CMAKE_SOURCE_DIR}/os/emscripten/pre.js")
367     target_link_libraries(WASM::WASM INTERFACE "--shell-file ${CMAKE_SOURCE_DIR}/os/emscripten/shell.html")
369     # Build the .html (which builds the .js, .wasm, and .data too).
370     set_target_properties(openttd PROPERTIES SUFFIX ".html")
371     target_link_libraries(openttd WASM::WASM)
372 endif()
374 if(NOT PERSONAL_DIR STREQUAL "(not set)")
375     add_definitions(
376         -DWITH_PERSONAL_DIR
377         -DPERSONAL_DIR="${PERSONAL_DIR}"
378     )
379 endif()
381 if(NOT SHARED_DIR STREQUAL "(not set)")
382     add_definitions(
383         -DWITH_SHARED_DIR
384         -DSHARED_DIR="${SHARED_DIR}"
385     )
386 endif()
388 if(NOT GLOBAL_DIR STREQUAL "(not set)")
389     add_definitions(
390         -DGLOBAL_DATA_DIR="${GLOBAL_DIR}"
391     )
392 endif()
394 link_package(SSE)
396 add_definitions_based_on_options()
398 if(WIN32)
399     add_definitions(
400         -DUNICODE
401         -D_UNICODE
402         -DWITH_UNISCRIBE
403         -DPSAPI_VERSION=1
404     )
406     target_link_libraries(openttd_lib
407         ws2_32
408         winmm
409         imm32
410         usp10
411         psapi
412         winhttp
413     )
414 endif()
416 if(CMAKE_SIZEOF_VOID_P EQUAL 8)
417     add_definitions(-DPOINTER_IS_64BIT)
418 endif()
420 include(CreateRegression)
421 create_regression()
423 if(APPLE OR WIN32)
424     find_package(Pandoc)
425 endif()
427 include(InstallAndPackage)