diff --git a/.gitignore b/.gitignore index 3e74133dfe..156a9f7a66 100644 --- a/.gitignore +++ b/.gitignore @@ -21,18 +21,13 @@ bin/scripts/* !bin/scripts/*.example !bin/scripts/readme.txt -*.aps bundle/* bundles/* docs/aidocs/* docs/gamedocs/* docs/source/* -.kdev4 -.kdev4/* -*.kdev4 media/openttd.desktop media/openttd.desktop.install -objs/* projects/.vs projects/Debug projects/Release @@ -44,8 +39,6 @@ projects/*.vcproj.*.user projects/*.vcxproj.user projects/*.VC.db projects/*.VC.opendb -src/rev.cpp -src/os/windows/ottdres.rc /Makefile* !/Makefile.msvc diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000000..c1ffa9ecca --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,226 @@ +cmake_minimum_required(VERSION 3.5) + +project(OpenTTD) + +if (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + message(FATAL_ERROR "In-source builds not allowed. Please run \"cmake ..\" from the bin directory") +endif (CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake") + +include(Options) +set_options() +set_directory_options() + +include(Static) +set_static_if_needed() + +# Prefer -pthread over -lpthread, which is often the better option of the two. +set(CMAKE_THREAD_PREFER_PTHREAD YES) +# Make sure we have Threads available. +find_package(Threads REQUIRED) + +find_package(ZLIB) +find_package(LibLZMA) +find_package(LZO) +find_package(PNG) +if (NOT WIN32) + find_package(SDL2) + if (NOT SDL2_FOUND) + find_package(SDL) + endif( NOT SDL2_FOUND) + find_package(Allegro) + find_package(Fluidsynth) + find_package(Freetype) + find_package(Fontconfig) + find_package(ICU OPTIONAL_COMPONENTS i18n lx) + find_package(XDG_basedir) +endif (NOT WIN32) +if (APPLE) + find_package(Iconv) + + find_library(AUDIOTOOLBOX_LIBRARY AudioToolbox) + find_library(AUDIOUNIT_LIBRARY AudioUnit) + find_library(COCOA_LIBRARY Cocoa) +endif (APPLE) + +if (MSVC) + find_package(Editbin REQUIRED) +endif (MSVC) + +find_package(SSE) +find_package(Xaudio2) + +find_package(Grfcodec) + +# IPO is only properly supported from CMake 3.9. Despite the fact we are +# CMake 3.5, still enable IPO if we detect we are 3.9+. +if (POLICY CMP0069) + cmake_policy(SET CMP0069 NEW) + include(CheckIPOSupported) + check_ipo_supported(RESULT IPO_FOUND) +endif (POLICY CMP0069) + +show_options() + +if (UNIX AND NOT APPLE AND NOT OPTION_DEDICATED) + if (NOT SDL_FOUND AND NOT SDL2_FOUND) + message(FATAL_ERROR "SDL or SDL2 is required for this platform") + endif (NOT SDL_FOUND AND NOT SDL2_FOUND) +endif (UNIX AND NOT APPLE AND NOT OPTION_DEDICATED) +if (APPLE) + if (NOT AUDIOTOOLBOX_LIBRARY) + message(FATAL_ERROR "AudioToolbox is required for this platform") + endif (NOT AUDIOTOOLBOX_LIBRARY) + if (NOT AUDIOUNIT_LIBRARY) + message(FATAL_ERROR "AudioUnit is required for this platform") + endif (NOT AUDIOUNIT_LIBRARY) + if (NOT COCOA_LIBRARY) + message(FATAL_ERROR "Cocoa is required for this platform") + endif (NOT COCOA_LIBRARY) +endif (APPLE) + +if (MSVC) + # C++17 for MSVC + set(CMAKE_CXX_STANDARD 17) +else (MSVC) + # C++11 for all other targets + set(CMAKE_CXX_STANDARD 11) +endif (MSVC) + +set(CMAKE_CXX_STANDARD_REQUIRED YES) +set(CMAKE_CXX_EXTENSIONS NO) + +list(APPEND GENERATED_SOURCE_FILES "${CMAKE_BINARY_DIR}/generated/rev.cpp") +if (WIN32) + list(APPEND GENERATED_SOURCE_FILES "${CMAKE_BINARY_DIR}/generated/ottdres.rc") +endif (WIN32) + +# Generate a target to determine version, which is execute every 'make' run +add_custom_target(find_version + ${CMAKE_COMMAND} + -DFIND_VERSION_BINARY_DIR=${CMAKE_BINARY_DIR}/generated + -DCPACK_BINARY_DIR=${CMAKE_BINARY_DIR} + -P "${CMAKE_SOURCE_DIR}/cmake/scripts/FindVersion.cmake" + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + BYPRODUCTS ${GENERATED_SOURCE_FILES} +) + +include(SourceList) +include(Endian) +add_endian_definition() + +# Needed by rev.cpp +include_directories(${CMAKE_SOURCE_DIR}/src) +# Needed by everything that uses Squirrel +include_directories(${CMAKE_SOURCE_DIR}/src/3rdparty/squirrel/include) + +include(CompileFlags) +compile_flags() + +add_executable(openttd WIN32 ${GENERATED_SOURCE_FILES}) +# All other files are added via target_sources() + +include(AddCustomXXXTimestamp) +add_subdirectory(${CMAKE_SOURCE_DIR}/src) +add_subdirectory(${CMAKE_SOURCE_DIR}/media/baseset) + +add_dependencies(openttd + find_version) + +target_link_libraries(openttd + openttd::languages + openttd::settings + openttd::basesets + Threads::Threads +) + +if (IPO_FOUND) + set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELEASE True) + set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_MINSIZEREL True) + set_target_properties(openttd PROPERTIES INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO True) +endif (IPO_FOUND) +set_target_properties(openttd PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}/bin") +process_compile_flags() + +if (APPLE OR UNIX) + add_definitions(-DUNIX) +endif (APPLE OR UNIX) + +include(LinkPackage) +link_package(PNG TARGET PNG::PNG ENCOURAGED) +link_package(ZLIB TARGET ZLIB::ZLIB ENCOURAGED) +link_package(LIBLZMA TARGET LibLZMA::LibLZMA ENCOURAGED) +link_package(LZO ENCOURAGED) +link_package(XDG_basedir) + +if (NOT OPTION_DEDICATED) + link_package(Fluidsynth) + link_package(SDL) + link_package(SDL2) + link_package(Allegro) + link_package(FREETYPE TARGET Freetype::Freetype) + link_package(Fontconfig TARGET Fontconfig::Fontconfig) + link_package(ICU_lx) + link_package(ICU_i18n) +endif (NOT OPTION_DEDICATED) + +if (APPLE) + link_package(Iconv TARGET Iconv::Iconv) + + target_link_libraries(openttd + ${AUDIOTOOLBOX_LIBRARY} + ${AUDIOUNIT_LIBRARY} + ${COCOA_LIBRARY} + ) + + add_definitions( + -DWITH_COCOA + -DENABLE_COCOA_QUARTZ + ) +endif (APPLE) + +if (NOT PERSONAL_DIR STREQUAL "(not set)") + add_definitions( + -DWITH_PERSONAL_DIR + -DPERSONAL_DIR="${PERSONAL_DIR}" + ) +endif (NOT PERSONAL_DIR STREQUAL "(not set)") + +if (NOT SHARED_DIR STREQUAL "(not set)") + add_definitions( + -DWITH_SHARED_DIR + -DSHARED_DIR="${SHARED_DIR}" + ) +endif (NOT SHARED_DIR STREQUAL "(not set)") + +if (NOT GLOBAL_DIR STREQUAL "(not set)") + add_definitions( + -DGLOBAL_DATA_DIR="${GLOBAL_DIR}" + ) +endif (NOT GLOBAL_DIR STREQUAL "(not set)") + +link_package(SSE) + +add_definitions_based_on_options() + +if (WIN32) + add_definitions( + -DUNICODE + -D_UNICODE + -DWITH_UNISCRIBE + ) + + target_link_libraries(openttd + ws2_32 + winmm + imm32 + ) +endif (WIN32) + +if (CMAKE_SIZEOF_VOID_P EQUAL 8) + add_definitions(-D_SQ64) +endif (CMAKE_SIZEOF_VOID_P EQUAL 8) + +include(CreateRegression) +create_regression() diff --git a/cmake/AddCustomXXXTimestamp.cmake b/cmake/AddCustomXXXTimestamp.cmake new file mode 100644 index 0000000000..ca93988731 --- /dev/null +++ b/cmake/AddCustomXXXTimestamp.cmake @@ -0,0 +1,145 @@ +macro(_parse_arguments_with_multi_hack ORIGINAL_COMMAND_LINE) + # cmake_parse_arguments() put all the MULTIS in a single variable; you + # lose the ability to see for example multiple COMMANDs. To be able to + # passthrough multiple MULTIS, we add a marker after every MULTI. This + # allows us to reassemble the correct amount again before giving it to + # the wrapped command with _reassemble_command_line(). + + set(COMMAND_LINE "${ORIGINAL_COMMAND_LINE}") + + foreach(MULTI IN LISTS MULTIS) + string(REPLACE "${MULTI}" "${MULTI};:::" COMMAND_LINE "${COMMAND_LINE}") + endforeach(MULTI) + + cmake_parse_arguments(PARAM "${OPTIONS}" "${SINGLES}" "${MULTIS}" ${COMMAND_LINE}) +endmacro() + +macro(_reassemble_command_line) + # Reassemble the command line as we original got it. + set(NEW_COMMAND_LINE ${PARAM_UNPARSED_ARGUMENTS}) + + foreach(OPTION IN LISTS OPTIONS) + if (PARAM_${OPTION}) + list(APPEND NEW_COMMAND_LINE "${OPTION}") + endif (PARAM_${OPTION}) + endforeach(OPTION) + + foreach(SINGLE IN LISTS SINGLES) + if (PARAM_${SINGLE}) + list(APPEND NEW_COMMAND_LINE "${SINGLE}" "${PARAM_${SINGLE}}") + endif (PARAM_${SINGLE}) + endforeach(SINGLE) + + foreach(MULTI IN LISTS MULTIS) + if (PARAM_${MULTI}) + # Replace our special marker with the name of the MULTI again. This + # restores for example multiple COMMANDs again. + string(REPLACE ":::" "${MULTI}" PARAM_${MULTI} "${PARAM_${MULTI}}") + list(APPEND NEW_COMMAND_LINE "${PARAM_${MULTI}}") + endif (PARAM_${MULTI}) + endforeach(MULTI) +endmacro() + +# Generated files can be older than their dependencies, causing useless +# regenerations. This function replaces each file in OUTPUT with a .timestamp +# file, adds a command to touch it and move the original file in BYPRODUCTS, +# before calling add_custom_command(). +# +# Note: Any add_custom_target() depending on files in original OUTPUT must use +# add_custom_target_timestamp() instead to have the correct dependencies. +# +# add_custom_command_timestamp(OUTPUT output1 [output2 ...] +# COMMAND command1 [ARGS] [args1...] +# [COMMAND command2 [ARGS] [args2...] ...] +# [MAIN_DEPENDENCY depend] +# [DEPENDS [depends...]] +# [BYPRODUCTS [files...]] +# [IMPLICIT_DEPENDS depend1 +# [ depend2] ...] +# [WORKING_DIRECTORY dir] +# [COMMENT comment] +# [VERBATIM] [APPEND] [USES_TERMINAL]) +function(add_custom_command_timestamp) + set(OPTIONS VERBATIM APPEND USES_TERMINAL) + set(SINGLES MAIN_DEPENDENCY WORKING_DIRECTORY COMMENT) + set(MULTIS OUTPUT COMMAND DEPENDS BYPRODUCTS IMPLICIT_DEPENDS) + + _parse_arguments_with_multi_hack("${ARGN}") + + # Create a list of all the OUTPUTs (by removing our magic marker) + string(REPLACE ":::;" "" OUTPUTS "${PARAM_OUTPUT}") + + # Reset the OUTPUT and BYPRODUCTS as an empty list (if needed). + # Because they are MULTIS, we need to add our special marker here. + set(PARAM_OUTPUT ":::") + if (NOT PARAM_BYPRODUCTS) + set(PARAM_BYPRODUCTS ":::") + endif () + + foreach(OUTPUT IN LISTS OUTPUTS) + # For every output, we add a 'cmake -E touch' entry to update the + # timestamp on each run. + get_filename_component(OUTPUT_FILENAME ${OUTPUT} NAME) + string(APPEND PARAM_COMMAND ";:::;${CMAKE_COMMAND};-E;touch;${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp") + + # We change the OUTPUT to a '.timestamp' variant, and make the real + # output a byproduct. + list(APPEND PARAM_OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp) + list(APPEND PARAM_BYPRODUCTS ${OUTPUT}) + + # Mark this file as being a byproduct; we use this again with + # add_custom_target_timestamp() to know if we should point to the + # '.timestamp' variant or not. + set_source_files_properties(${OUTPUT} PROPERTIES BYPRODUCT ${CMAKE_CURRENT_BINARY_DIR}/${OUTPUT_FILENAME}.timestamp) + endforeach(OUTPUT) + + # Reassemble and call the wrapped command + _reassemble_command_line() + add_custom_command(${NEW_COMMAND_LINE}) +endfunction(add_custom_command_timestamp) + +# Generated files can be older than their dependencies, causing useless +# regenerations. This function adds a .timestamp file for each file in DEPENDS +# replaced by add_custom_command_timestamp(), before calling add_custom_target(). +# +# add_custom_target_timestamp(Name [ALL] [command1 [args1...]] +# [COMMAND command2 [args2...] ...] +# [DEPENDS depend depend depend ... ] +# [BYPRODUCTS [files...]] +# [WORKING_DIRECTORY dir] +# [COMMENT comment] +# [VERBATIM] [USES_TERMINAL] +# [SOURCES src1 [src2...]]) +function(add_custom_target_timestamp) + set(OPTIONS VERBATIM USES_TERMINAL) + set(SINGLES WORKING_DIRECTORY COMMENT) + set(MULTIS COMMAND DEPENDS BYPRODUCTS SOURCES) + # ALL is missing, as the order is important here. It will be picked up + # by ${PARAM_UNPARSED_ARGUMENTS} when reassembling the command line. + + _parse_arguments_with_multi_hack("${ARGN}") + + # Create a list of all the DEPENDs (by removing our magic marker) + string(REPLACE ":::;" "" DEPENDS "${PARAM_DEPENDS}") + + # Reset the DEPEND as an empty list. + # Because it is a MULTI, we need to add our special marker here. + set(PARAM_DEPENDS ":::") + + foreach(DEPEND IN LISTS DEPENDS) + # Check if the output is produced by add_custom_command_timestamp() + get_source_file_property(BYPRODUCT ${DEPEND} BYPRODUCT) + + if (BYPRODUCT STREQUAL "NOTFOUND") + # If it is not, just keep it as DEPEND + list(APPEND PARAM_DEPENDS "${DEPEND}") + else (BYPRODUCT STREQUAL "NOTFOUND") + # If it is, the BYPRODUCT property points to the timestamp we want to depend on + list(APPEND PARAM_DEPENDS "${BYPRODUCT}") + endif (BYPRODUCT STREQUAL "NOTFOUND") + endforeach(DEPEND) + + # Reassemble and call the wrapped command + _reassemble_command_line() + add_custom_target(${NEW_COMMAND_LINE}) +endfunction(add_custom_target_timestamp) diff --git a/cmake/CompileFlags.cmake b/cmake/CompileFlags.cmake new file mode 100644 index 0000000000..05c19abab9 --- /dev/null +++ b/cmake/CompileFlags.cmake @@ -0,0 +1,120 @@ +# Macro which contains all bits to setup the compile flags correctly. +# +# compile_flags() +# +macro(compile_flags) + if (MSVC) + # Switch to MT (static) instead of MD (dynamic) binary + + # For MSVC two generators are available + # - a command line generator (Ninja) using CMAKE_BUILD_TYPE to specify the + # configuration of the build tree + # - an IDE generator (Visual Studio) using CMAKE_CONFIGURATION_TYPES to + # specify all configurations that will be available in the generated solution + list(APPEND MSVC_CONFIGS "${CMAKE_BUILD_TYPE}" "${CMAKE_CONFIGURATION_TYPES}") + + # Set usage of static runtime for all configurations + foreach(MSVC_CONFIG ${MSVC_CONFIGS}) + string(TOUPPER "CMAKE_CXX_FLAGS_${MSVC_CONFIG}" MSVC_FLAGS) + string(REPLACE "/MD" "/MT" ${MSVC_FLAGS} "${${MSVC_FLAGS}}") + endforeach() + + # "If /Zc:rvalueCast is specified, the compiler follows section 5.4 of the + # C++11 standard". We need C++11 for the way we use threads. + add_compile_options(/Zc:rvalueCast) + + # Add DPI manifest to project; other WIN32 targets get this via ottdres.rc + list(APPEND GENERATED_SOURCE_FILES "${CMAKE_SOURCE_DIR}/os/windows/openttd.manifest") + endif (MSVC) + + # Add some -D flags for Debug builds. We cannot use add_definitions(), because + # it does not appear to support the $<> tags. + add_compile_options( + "$<$:-D_DEBUG>" + "$<$:-D_FORTIFY_SOURCE=2>" + ) + + # Prepare a generator that checks if we are not a debug, and don't have asserts + # on. We need this later on to set some compile options for stable releases. + set(IS_STABLE_RELEASE "$>,$>>") + + if (MSVC) + add_compile_options(/W3) + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + add_compile_options( + -W + -Wall + -Wcast-qual + -Wextra + -Wsign-compare + -Wundef + -Wpointer-arith + -Wwrite-strings + -Wredundant-decls + -Wformat-security + -Wformat=2 + -Winit-self + -Wnon-virtual-dtor + + # Often parameters are unused, which is fine. + -Wno-unused-parameter + # We use 'ABCD' multichar for SaveLoad chunks identifiers + -Wno-multichar + + # Compilers complains about that we break strict-aliasing. + # On most places we don't see how to fix it, and it doesn't + # break anything. So disable strict-aliasing to make the + # compiler all happy. + -fno-strict-aliasing + ) + + add_compile_options( + # When we are a stable release (Release build + USE_ASSERTS not set), + # assertations are off, which trigger a lot of warnings. We disable + # these warnings for these releases. + "$<${IS_STABLE_RELEASE}:-Wno-unused-variable>" + "$<${IS_STABLE_RELEASE}:-Wno-unused-but-set-parameter>" + "$<${IS_STABLE_RELEASE}:-Wno-unused-but-set-variable>" + ) + + if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + include(CheckCXXCompilerFlag) + check_cxx_compiler_flag("-flifetime-dse=1" LIFETIME_DSE_FOUND) + + add_compile_options( + # GCC 4.2+ automatically assumes that signed overflows do + # not occur in signed arithmetics, whereas we are not + # sure that they will not happen. It furthermore complains + # about its own optimized code in some places. + "-fno-strict-overflow" + + # Prevent optimisation supposing enums are in a range specified by the standard + # For details, see http://gcc.gnu.org/PR43680 + "-fno-tree-vrp" + + # -flifetime-dse=2 (default since GCC 6) doesn't play + # well with our custom pool item allocator + "$<$:-flifetime-dse=1>" + ) + endif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") + add_compile_options( + -Wall + # warning #873: function ... ::operator new ... has no corresponding operator delete ... + -wd873 + # warning #1292: unknown attribute "fallthrough" + -wd1292 + # warning #1899: multicharacter character literal (potential portability problem) + -wd1899 + # warning #2160: anonymous union qualifier is ignored + -wd2160 + ) + else () + message(FATAL_ERROR "No warning flags are set for this compiler yet; please consider creating a Pull Request to add support for this compiler.") + endif () + + if (NOT WIN32) + # rdynamic is used to get useful stack traces from crash reports. + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -rdynamic") + endif (NOT WIN32) +endmacro() diff --git a/cmake/CreateGrfCommand.cmake b/cmake/CreateGrfCommand.cmake new file mode 100644 index 0000000000..25e599f568 --- /dev/null +++ b/cmake/CreateGrfCommand.cmake @@ -0,0 +1,50 @@ +# Macro which contains all bits and pieces to create a single grf file based +# on NFO and PNG files. +# +# create_grf_command() +# +function(create_grf_command) + set(EXTRA_PNG_SOURCE_FILES ${ARGV}) + + get_filename_component(GRF_SOURCE_FOLDER_NAME "${CMAKE_CURRENT_SOURCE_DIR}" NAME) + get_filename_component(GRF_BINARY_FILE ${CMAKE_CURRENT_SOURCE_DIR}/../${GRF_SOURCE_FOLDER_NAME}.grf ABSOLUTE) + file(GLOB_RECURSE GRF_PNG_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.png) + file(GLOB_RECURSE GRF_NFO_SOURCE_FILES ${CMAKE_CURRENT_SOURCE_DIR}/*.nfo) + set(GRF_PNG_SOURCE_FILES ${GRF_PNG_SOURCE_FILES} ${EXTRA_PNG_SOURCE_FILES}) + + # Copy over all the PNG files to the correct folder + foreach(GRF_PNG_SOURCE_FILE IN LISTS GRF_PNG_SOURCE_FILES) + get_filename_component(GRF_PNG_SOURCE_FILE_NAME "${GRF_PNG_SOURCE_FILE}" NAME) + set(GRF_PNG_BINARY_FILE "${CMAKE_CURRENT_BINARY_DIR}/sprites/${GRF_PNG_SOURCE_FILE_NAME}") + + add_custom_command(OUTPUT ${GRF_PNG_BINARY_FILE} + COMMAND ${CMAKE_COMMAND} -E copy + ${GRF_PNG_SOURCE_FILE} + ${GRF_PNG_BINARY_FILE} + MAIN_DEPENDENCY ${GRF_PNG_SOURCE_FILE} + COMMENT "Copying ${GRF_PNG_SOURCE_FILE_NAME} sprite file" + ) + + list(APPEND GRF_PNG_BINARY_FILES ${GRF_PNG_BINARY_FILE}) + endforeach(GRF_PNG_SOURCE_FILE) + + add_custom_command(OUTPUT ${GRF_BINARY_FILE} + COMMAND ${CMAKE_COMMAND} + -DGRF_SOURCE_FOLDER=${CMAKE_CURRENT_SOURCE_DIR} + -DGRF_BINARY_FILE=${GRF_BINARY_FILE} + -DNFORENUM_EXECUTABLE=${NFORENUM_EXECUTABLE} + -DGRFCODEC_EXECUTABLE=${GRFCODEC_EXECUTABLE} + -P ${CMAKE_SOURCE_DIR}/cmake/scripts/CreateGRF.cmake + MAIN_DEPENDENCY ${GRF_NFO_SOURCE_FILES} + DEPENDS ${GRF_PNG_BINARY_FILES} + ${CMAKE_SOURCE_DIR}/cmake/scripts/CreateGRF.cmake + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating ${GRF_SOURCE_FOLDER_NAME}.grf" + ) + + # For conviance, if you want to only test building the GRF + add_custom_target(${GRF_SOURCE_FOLDER_NAME}.grf + DEPENDS + ${GRF_BINARY_FILE} + ) +endfunction() diff --git a/cmake/CreateRegression.cmake b/cmake/CreateRegression.cmake new file mode 100644 index 0000000000..443332368a --- /dev/null +++ b/cmake/CreateRegression.cmake @@ -0,0 +1,86 @@ +# Macro which contains all bits and pieces to create the regression tests. +# This creates both a standalone target 'regression', and it integrates with +# 'ctest'. The first is prefered, as it is more verbose, and takes care of +# dependencies correctly. +# +# create_regression() +# +macro(create_regression) + # Find all the files in the regression folder; they need to be copied to the + # build folder before we can run the regression + file(GLOB_RECURSE REGRESSION_SOURCE_FILES ${CMAKE_SOURCE_DIR}/regression/*) + foreach(REGRESSION_SOURCE_FILE IN LISTS REGRESSION_SOURCE_FILES) + string(REGEX REPLACE "^${CMAKE_SOURCE_DIR}/regression/" "${CMAKE_BINARY_DIR}/ai/" REGRESSION_BINARY_FILE "${REGRESSION_SOURCE_FILE}") + string(REGEX REPLACE "^${CMAKE_SOURCE_DIR}/regression/" "" REGRESSION_SOURCE_FILE_NAME "${REGRESSION_SOURCE_FILE}") + + if ("${REGRESSION_SOURCE_FILE_NAME}" STREQUAL "regression.cfg") + continue() + endif ("${REGRESSION_SOURCE_FILE_NAME}" STREQUAL "regression.cfg") + + add_custom_command(OUTPUT ${REGRESSION_BINARY_FILE} + COMMAND ${CMAKE_COMMAND} -E copy + ${REGRESSION_SOURCE_FILE} + ${REGRESSION_BINARY_FILE} + MAIN_DEPENDENCY ${REGRESSION_SOURCE_FILE} + COMMENT "Copying ${REGRESSION_SOURCE_FILE_NAME} regression file" + ) + + list(APPEND REGRESSION_BINARY_FILES ${REGRESSION_BINARY_FILE}) + endforeach(REGRESSION_SOURCE_FILE) + + # Copy the regression configuration in a special folder, so all autogenerated + # folders end up in the same place after running regression. + add_custom_command(OUTPUT ${CMAKE_BINARY_DIR}/regression/regression.cfg + COMMAND ${CMAKE_COMMAND} -E copy + ${CMAKE_SOURCE_DIR}/regression/regression.cfg + ${CMAKE_BINARY_DIR}/regression/regression.cfg + MAIN_DEPENDENCY ${CMAKE_SOURCE_DIR}/regression/regression.cfg + COMMENT "Copying ${REGRESSION_SOURCE_FILE_NAME} regression file" + ) + list(APPEND REGRESSION_BINARY_FILES ${CMAKE_BINARY_DIR}/regression/regression.cfg) + + # Create a new target which copies all regression files + add_custom_target(regression_files + ALL # this is needed because 'make test' doesn't resolve dependencies, and otherwise this is never executed + DEPENDS + ${REGRESSION_BINARY_FILES} + ) + + enable_testing() + + # Find all the tests we have, and create a target for them + file(GLOB REGRESSION_TESTS ${CMAKE_SOURCE_DIR}/regression/*) + foreach(REGRESSION_TEST IN LISTS REGRESSION_TESTS) + get_filename_component(REGRESSION_TEST_NAME "${REGRESSION_TEST}" NAME) + + if ("${REGRESSION_TEST_NAME}" STREQUAL "regression.cfg") + continue() + endif ("${REGRESSION_TEST_NAME}" STREQUAL "regression.cfg") + + add_custom_target(regression_${REGRESSION_TEST_NAME} + COMMAND ${CMAKE_COMMAND} + -DOPENTTD_EXECUTABLE=$ + -DEDITBIN_EXECUTABLE=${EDITBIN_EXECUTABLE} + -DREGRESSION_TEST=${REGRESSION_TEST_NAME} + -P "${CMAKE_SOURCE_DIR}/cmake/scripts/Regression.cmake" + DEPENDS openttd regression_files + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Running regression test ${REGRESSION_TEST_NAME}" + ) + + # Also make sure that 'make test' runs the regression + add_test(NAME regression_${REGRESSION_TEST_NAME} + COMMAND ${CMAKE_COMMAND} + -DOPENTTD_EXECUTABLE=$ + -DEDITBIN_EXECUTABLE=${EDITBIN_EXECUTABLE} + -DREGRESSION_TEST=${REGRESSION_TEST_NAME} + -P "${CMAKE_SOURCE_DIR}/cmake/scripts/Regression.cmake" + WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) + + list(APPEND REGRESSION_TARGETS regression_${REGRESSION_TEST_NAME}) + endforeach(REGRESSION_TEST) + + # Create a new target which runs the regression + add_custom_target(regression + DEPENDS ${REGRESSION_TARGETS}) +endmacro() diff --git a/cmake/Endian.cmake b/cmake/Endian.cmake new file mode 100644 index 0000000000..00cb975445 --- /dev/null +++ b/cmake/Endian.cmake @@ -0,0 +1,14 @@ +# Add the definitions to indicate which endian we are building for. +# +# add_endian_definition() +# +function(add_endian_definition) + include(TestBigEndian) + TEST_BIG_ENDIAN(IS_BIG_ENDIAN) + + if (IS_BIG_ENDIAN) + add_definitions(-DTTD_ENDIAN=TTD_BIG_ENDIAN) + else (IS_BIG_ENDIAN) + add_definitions(-DTTD_ENDIAN=TTD_LITTLE_ENDIAN) + endif (IS_BIG_ENDIAN) +endfunction() diff --git a/cmake/FindAllegro.cmake b/cmake/FindAllegro.cmake new file mode 100644 index 0000000000..85b2ffd392 --- /dev/null +++ b/cmake/FindAllegro.cmake @@ -0,0 +1,65 @@ +#[=======================================================================[.rst: +FindAllegro +------- + +Finds the allegro library. + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``Allegro_FOUND`` + True if the system has the allegro library. +``Allegro_INCLUDE_DIRS`` + Include directories needed to use allegro. +``Allegro_LIBRARIES`` + Libraries needed to link to allegro. +``Allegro_VERSION`` + The version of the allegro library which was found. + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``Allegro_INCLUDE_DIR`` + The directory containing ``allegro.h``. +``Allegro_LIBRARY`` + The path to the allegro library. + +#]=======================================================================] + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_Allegro QUIET allegro) + +find_path(Allegro_INCLUDE_DIR + NAMES allegro.h + PATHS ${PC_Allegro_INCLUDE_DIRS} +) + +find_library(Allegro_LIBRARY + NAMES alleg + PATHS ${PC_Allegro_LIBRARY_DIRS} +) + +set(Allegro_VERSION ${PC_Allegro_VERSION}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Allegro + FOUND_VAR Allegro_FOUND + REQUIRED_VARS + Allegro_LIBRARY + Allegro_INCLUDE_DIR + VERSION_VAR Allegro_VERSION +) + +if (Allegro_FOUND) + set(Allegro_LIBRARIES ${Allegro_LIBRARY}) + set(Allegro_INCLUDE_DIRS ${Allegro_INCLUDE_DIR}) +endif () + +mark_as_advanced( + Allegro_INCLUDE_DIR + Allegro_LIBRARY +) diff --git a/cmake/FindEditbin.cmake b/cmake/FindEditbin.cmake new file mode 100644 index 0000000000..363bc00539 --- /dev/null +++ b/cmake/FindEditbin.cmake @@ -0,0 +1,13 @@ +# Autodetect editbin. Only useful for MSVC. + +get_filename_component(MSVC_COMPILE_DIRECTORY ${CMAKE_CXX_COMPILER} DIRECTORY) +find_program( + EDITBIN_EXECUTABLE editbin.exe + HINTS ${MSVC_COMPILE_DIRECTORY} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Editbin + FOUND_VAR EDITBIN_FOUND + REQUIRED_VARS EDITBIN_EXECUTABLE +) diff --git a/cmake/FindFluidsynth.cmake b/cmake/FindFluidsynth.cmake new file mode 100644 index 0000000000..063726dbe5 --- /dev/null +++ b/cmake/FindFluidsynth.cmake @@ -0,0 +1,65 @@ +#[=======================================================================[.rst: +FindFluidsynth +------- + +Finds the fluidsynth library. + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``Fluidsynth_FOUND`` + True if the system has the fluidsynth library. +``Fluidsynth_INCLUDE_DIRS`` + Include directories needed to use fluidsynth. +``Fluidsynth_LIBRARIES`` + Libraries needed to link to fluidsynth. +``Fluidsynth_VERSION`` + The version of the fluidsynth library which was found. + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``Fluidsynth_INCLUDE_DIR`` + The directory containing ``fluidsynth.h``. +``Fluidsynth_LIBRARY`` + The path to the fluidsynth library. + +#]=======================================================================] + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_Fluidsynth QUIET fluidsynth) + +find_path(Fluidsynth_INCLUDE_DIR + NAMES fluidsynth.h + PATHS ${PC_Fluidsynth_INCLUDE_DIRS} +) + +find_library(Fluidsynth_LIBRARY + NAMES fluidsynth + PATHS ${PC_Fluidsynth_LIBRARY_DIRS} +) + +set(Fluidsynth_VERSION ${PC_Fluidsynth_VERSION}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Fluidsynth + FOUND_VAR Fluidsynth_FOUND + REQUIRED_VARS + Fluidsynth_LIBRARY + Fluidsynth_INCLUDE_DIR + VERSION_VAR Fluidsynth_VERSION +) + +if (Fluidsynth_FOUND) + set(Fluidsynth_LIBRARIES ${Fluidsynth_LIBRARY}) + set(Fluidsynth_INCLUDE_DIRS ${Fluidsynth_INCLUDE_DIR}) +endif () + +mark_as_advanced( + Fluidsynth_INCLUDE_DIR + Fluidsynth_LIBRARY +) diff --git a/cmake/FindFontconfig.cmake b/cmake/FindFontconfig.cmake new file mode 100644 index 0000000000..a6f0180b37 --- /dev/null +++ b/cmake/FindFontconfig.cmake @@ -0,0 +1,101 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindFontconfig +-------------- + +Find Fontconfig headers and library. + +Imported Targets +^^^^^^^^^^^^^^^^ + +``Fontconfig::Fontconfig`` + The Fontconfig library, if found. + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables in your project: + +``Fontconfig_FOUND`` + true if (the requested version of) Fontconfig is available. +``Fontconfig_VERSION`` + the version of Fontconfig. +``Fontconfig_LIBRARIES`` + the libraries to link against to use Fontconfig. +``Fontconfig_INCLUDE_DIRS`` + where to find the Fontconfig headers. +``Fontconfig_COMPILE_OPTIONS`` + this should be passed to target_compile_options(), if the + target is not used for linking + +#]=======================================================================] + + +# use pkg-config to get the directories and then use these values +# in the FIND_PATH() and FIND_LIBRARY() calls +find_package(PkgConfig QUIET) +pkg_check_modules(PKG_FONTCONFIG QUIET fontconfig) +set(Fontconfig_COMPILE_OPTIONS ${PKG_FONTCONFIG_CFLAGS_OTHER}) +set(Fontconfig_VERSION ${PKG_FONTCONFIG_VERSION}) + +find_path( Fontconfig_INCLUDE_DIR + NAMES + fontconfig/fontconfig.h + HINTS + ${PKG_FONTCONFIG_INCLUDE_DIRS} + /usr/X11/include +) + +find_library( Fontconfig_LIBRARY + NAMES + fontconfig + PATHS + ${PKG_FONTCONFIG_LIBRARY_DIRS} +) + +if (Fontconfig_INCLUDE_DIR AND NOT Fontconfig_VERSION) + file(STRINGS ${Fontconfig_INCLUDE_DIR}/fontconfig/fontconfig.h _contents REGEX "^#define[ \t]+FC_[A-Z]+[ \t]+[0-9]+$") + unset(Fontconfig_VERSION) + foreach(VPART MAJOR MINOR REVISION) + foreach(VLINE ${_contents}) + if(VLINE MATCHES "^#define[\t ]+FC_${VPART}[\t ]+([0-9]+)$") + set(Fontconfig_VERSION_PART "${CMAKE_MATCH_1}") + if(Fontconfig_VERSION) + string(APPEND Fontconfig_VERSION ".${Fontconfig_VERSION_PART}") + else() + set(Fontconfig_VERSION "${Fontconfig_VERSION_PART}") + endif() + endif() + endforeach() + endforeach() +endif () + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Fontconfig + FOUND_VAR + Fontconfig_FOUND + REQUIRED_VARS + Fontconfig_LIBRARY + Fontconfig_INCLUDE_DIR + VERSION_VAR + Fontconfig_VERSION +) + + +if(Fontconfig_FOUND AND NOT TARGET Fontconfig::Fontconfig) + add_library(Fontconfig::Fontconfig UNKNOWN IMPORTED) + set_target_properties(Fontconfig::Fontconfig PROPERTIES + IMPORTED_LOCATION "${Fontconfig_LIBRARY}" + INTERFACE_COMPILE_OPTIONS "${Fontconfig_COMPILE_OPTIONS}" + INTERFACE_INCLUDE_DIRECTORIES "${Fontconfig_INCLUDE_DIR}" + ) +endif() + +mark_as_advanced(Fontconfig_LIBRARY Fontconfig_INCLUDE_DIR) + +if(Fontconfig_FOUND) + set(Fontconfig_LIBRARIES ${Fontconfig_LIBRARY}) + set(Fontconfig_INCLUDE_DIRS ${Fontconfig_INCLUDE_DIR}) +endif() diff --git a/cmake/FindGrfcodec.cmake b/cmake/FindGrfcodec.cmake new file mode 100644 index 0000000000..089f956706 --- /dev/null +++ b/cmake/FindGrfcodec.cmake @@ -0,0 +1,13 @@ +# Autodetect grfcodec and nforenum. +# + +find_program(GRFCODEC_EXECUTABLE grfcodec) +find_program(NFORENUM_EXECUTABLE nforenum) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(Grfcodec + FOUND_VAR GRFCODEC_FOUND + REQUIRED_VARS + GRFCODEC_EXECUTABLE + NFORENUM_EXECUTABLE +) diff --git a/cmake/FindICU.cmake b/cmake/FindICU.cmake new file mode 100644 index 0000000000..471e43c1d9 --- /dev/null +++ b/cmake/FindICU.cmake @@ -0,0 +1,64 @@ +#[=======================================================================[.rst: +FindICU +------- + +Finds components of the ICU library. + +Accepted components are: uc, i18n, le, lx, io + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``ICU_FOUND`` + True if components of ICU library are found. +``ICU_VERSION`` + The version of the ICU library which was found. +``ICU__FOUND`` + True if the system has the component of ICU library. +``ICU__INCLUDE_DIRS`` + Include directories needed to use the component of ICU library. +``ICU__LIBRARIES`` + Libraries needed to link to the component of ICU library. + +#]=======================================================================] + +find_package(PkgConfig QUIET) + +set(ICU_KNOWN_COMPONENTS "uc" "i18n" "le" "lx" "io") + +foreach(MOD_NAME IN LISTS ICU_FIND_COMPONENTS) + if (NOT MOD_NAME IN_LIST ICU_KNOWN_COMPONENTS) + message(FATAL_ERROR "Unknown ICU component: ${MOD_NAME}") + endif() + pkg_check_modules(PC_ICU_${MOD_NAME} QUIET icu-${MOD_NAME}) + + # Check the libraries returned by pkg-config really exist. + unset(PC_LIBRARIES) + foreach(LIBRARY IN LISTS PC_ICU_${MOD_NAME}_LIBRARIES) + unset(PC_LIBRARY CACHE) + find_library(PC_LIBRARY NAMES ${LIBRARY}) + if (NOT PC_LIBRARY) + unset(PC_ICU_${MOD_NAME}_FOUND) + endif() + list(APPEND PC_LIBRARIES ${PC_LIBRARY}) + endforeach() + unset(PC_LIBRARY CACHE) + + if (${PC_ICU_${MOD_NAME}_FOUND}) + set(ICU_COMPONENT_FOUND TRUE) + set(ICU_${MOD_NAME}_FOUND TRUE) + set(ICU_${MOD_NAME}_LIBRARIES ${PC_LIBRARIES}) + set(ICU_${MOD_NAME}_INCLUDE_DIRS ${PC_ICU_${MOD_NAME}_INCLUDE_DIRS}) + set(ICU_VERSION ${PC_ICU_${MOD_NAME}_VERSION}) + endif() +endforeach() + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(ICU + FOUND_VAR ICU_FOUND + REQUIRED_VARS ICU_COMPONENT_FOUND + VERSION_VAR ICU_VERSION + HANDLE_COMPONENTS +) diff --git a/cmake/FindIconv.cmake b/cmake/FindIconv.cmake new file mode 100644 index 0000000000..5185601ab7 --- /dev/null +++ b/cmake/FindIconv.cmake @@ -0,0 +1,133 @@ +# Distributed under the OSI-approved BSD 3-Clause License. See accompanying +# file Copyright.txt or https://cmake.org/licensing for details. + +#[=======================================================================[.rst: +FindIconv +--------- + +This module finds the ``iconv()`` POSIX.1 functions on the system. +These functions might be provided in the regular C library or externally +in the form of an additional library. + +The following variables are provided to indicate iconv support: + +.. variable:: Iconv_FOUND + + Variable indicating if the iconv support was found. + +.. variable:: Iconv_INCLUDE_DIRS + + The directories containing the iconv headers. + +.. variable:: Iconv_LIBRARIES + + The iconv libraries to be linked. + +.. variable:: Iconv_IS_BUILT_IN + + A variable indicating whether iconv support is stemming from the + C library or not. Even if the C library provides `iconv()`, the presence of + an external `libiconv` implementation might lead to this being false. + +Additionally, the following :prop_tgt:`IMPORTED` target is being provided: + +.. variable:: Iconv::Iconv + + Imported target for using iconv. + +The following cache variables may also be set: + +.. variable:: Iconv_INCLUDE_DIR + + The directory containing the iconv headers. + +.. variable:: Iconv_LIBRARY + + The iconv library (if not implicitly given in the C library). + +.. note:: + On POSIX platforms, iconv might be part of the C library and the cache + variables ``Iconv_INCLUDE_DIR`` and ``Iconv_LIBRARY`` might be empty. + +#]=======================================================================] + +include(CMakePushCheckState) +if(CMAKE_C_COMPILER_LOADED) + include(CheckCSourceCompiles) +elseif(CMAKE_CXX_COMPILER_LOADED) + include(CheckCXXSourceCompiles) +else() + # If neither C nor CXX are loaded, implicit iconv makes no sense. + set(Iconv_IS_BUILT_IN FALSE) +endif() + +# iconv can only be provided in libc on a POSIX system. +# If any cache variable is already set, we'll skip this test. +if(NOT DEFINED Iconv_IS_BUILT_IN) + if(UNIX AND NOT DEFINED Iconv_INCLUDE_DIR AND NOT DEFINED Iconv_LIBRARY) + cmake_push_check_state(RESET) + # We always suppress the message here: Otherwise on supported systems + # not having iconv in their C library (e.g. those using libiconv) + # would always display a confusing "Looking for iconv - not found" message + set(CMAKE_FIND_QUIETLY TRUE) + # The following code will not work, but it's sufficient to see if it compiles. + # Note: libiconv will define the iconv functions as macros, so CheckSymbolExists + # will not yield correct results. + set(Iconv_IMPLICIT_TEST_CODE + " + #include + #include + int main() { + char *a, *b; + size_t i, j; + iconv_t ic; + ic = iconv_open(\"to\", \"from\"); + iconv(ic, &a, &i, &b, &j); + iconv_close(ic); + } + " + ) + if(CMAKE_C_COMPILER_LOADED) + check_c_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN) + else() + check_cxx_source_compiles("${Iconv_IMPLICIT_TEST_CODE}" Iconv_IS_BUILT_IN) + endif() + cmake_pop_check_state() + else() + set(Iconv_IS_BUILT_IN FALSE) + endif() +endif() + +if(NOT Iconv_IS_BUILT_IN) + find_path(Iconv_INCLUDE_DIR + NAMES "iconv.h" + DOC "iconv include directory") + set(Iconv_LIBRARY_NAMES "iconv" "libiconv") +else() + set(Iconv_INCLUDE_DIR "" CACHE FILEPATH "iconv include directory") + set(Iconv_LIBRARY_NAMES "c") +endif() + +find_library(Iconv_LIBRARY + NAMES ${Iconv_LIBRARY_NAMES} + DOC "iconv library (potentially the C library)") + +mark_as_advanced(Iconv_INCLUDE_DIR) +mark_as_advanced(Iconv_LIBRARY) + +include(FindPackageHandleStandardArgs) +if(NOT Iconv_IS_BUILT_IN) + find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY Iconv_INCLUDE_DIR) +else() + find_package_handle_standard_args(Iconv REQUIRED_VARS Iconv_LIBRARY) +endif() + +if(Iconv_FOUND) + set(Iconv_INCLUDE_DIRS "${Iconv_INCLUDE_DIR}") + set(Iconv_LIBRARIES "${Iconv_LIBRARY}") + if(NOT TARGET Iconv::Iconv) + add_library(Iconv::Iconv INTERFACE IMPORTED) + endif() + set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_INCLUDE_DIRECTORIES "${Iconv_INCLUDE_DIRS}") + set_property(TARGET Iconv::Iconv PROPERTY INTERFACE_LINK_LIBRARIES "${Iconv_LIBRARIES}") +endif() diff --git a/cmake/FindLZO.cmake b/cmake/FindLZO.cmake new file mode 100644 index 0000000000..9a409002df --- /dev/null +++ b/cmake/FindLZO.cmake @@ -0,0 +1,89 @@ +#[=======================================================================[.rst: +FindLZO +------- + +Finds the LZO library. + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``LZO_FOUND`` + True if the system has the LZO library. +``LZO_INCLUDE_DIRS`` + Include directories needed to use LZO. +``LZO_LIBRARIES`` + Libraries needed to link to LZO. +``LZO_VERSION`` + The version of the LZO library which was found. + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``LZO_INCLUDE_DIR`` + The directory containing ``lzo/lzo1x.h``. +``LZO_LIBRARY`` + The path to the LZO library. + +#]=======================================================================] + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_LZO QUIET lzo2) + +find_path(LZO_INCLUDE_DIR + NAMES lzo/lzo1x.h + PATHS ${PC_LZO_INCLUDE_DIRS} +) + +find_library(LZO_LIBRARY + NAMES lzo2 + PATHS ${PC_LZO_LIBRARY_DIRS} +) + +# With vcpkg, the library path should contain both 'debug' and 'optimized' +# entries (see target_link_libraries() documentation for more information) +# +# NOTE: we only patch up when using vcpkg; the same issue might happen +# when not using vcpkg, but this is non-trivial to fix, as we have no idea +# what the paths are. With vcpkg we do. And we only official support vcpkg +# with Windows. +# +# NOTE: this is based on the assumption that the debug file has the same +# name as the optimized file. This is not always the case, but so far +# experiences has shown that in those case vcpkg CMake files do the right +# thing. +if (VCPKG_TOOLCHAIN AND LZO_LIBRARY) + if (LZO_LIBRARY MATCHES "/debug/") + set(LZO_LIBRARY_DEBUG ${LZO_LIBRARY}) + string(REPLACE "/debug/lib/" "/lib/" LZO_LIBRARY_RELEASE ${LZO_LIBRARY}) + else() + set(LZO_LIBRARY_RELEASE ${LZO_LIBRARY}) + string(REPLACE "/lib/" "/debug/lib/" LZO_LIBRARY_DEBUG ${LZO_LIBRARY}) + endif() + include(SelectLibraryConfigurations) + select_library_configurations(LZO) +endif() + +set(LZO_VERSION ${PC_LZO_VERSION}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(LZO + FOUND_VAR LZO_FOUND + REQUIRED_VARS + LZO_LIBRARY + LZO_INCLUDE_DIR + VERSION_VAR LZO_VERSION +) + +if (LZO_FOUND) + set(LZO_LIBRARIES ${LZO_LIBRARY}) + set(LZO_INCLUDE_DIRS ${LZO_INCLUDE_DIR}) +endif () + +mark_as_advanced( + LZO_INCLUDE_DIR + LZO_LIBRARY +) diff --git a/cmake/FindSSE.cmake b/cmake/FindSSE.cmake new file mode 100644 index 0000000000..d0a57ccbb2 --- /dev/null +++ b/cmake/FindSSE.cmake @@ -0,0 +1,17 @@ +# Autodetect if SSE4.1 can be used. If so, the assumption is, so can the other +# SSE version (SSE 2.0, SSSE 3.0). + +include(CheckCXXSourceCompiles) +set(CMAKE_REQUIRED_FLAGS "") + +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + set(CMAKE_REQUIRED_FLAGS "-msse4.1") +endif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + +check_cxx_source_compiles(" + #include + #include + #include + int main() { return 0; }" + SSE_FOUND +) diff --git a/cmake/FindXDG_basedir.cmake b/cmake/FindXDG_basedir.cmake new file mode 100644 index 0000000000..913b425e20 --- /dev/null +++ b/cmake/FindXDG_basedir.cmake @@ -0,0 +1,65 @@ +#[=======================================================================[.rst: +FindXDG_basedir +------- + +Finds the xdg-basedir library. + +Result Variables +^^^^^^^^^^^^^^^^ + +This will define the following variables: + +``XDG_basedir_FOUND`` + True if the system has the xdg-basedir library. +``XDG_basedir_INCLUDE_DIRS`` + Include directories needed to use xdg-basedir. +``XDG_basedir_LIBRARIES`` + Libraries needed to link to xdg-basedir. +``XDG_basedir_VERSION`` + The version of the xdg-basedir library which was found. + +Cache Variables +^^^^^^^^^^^^^^^ + +The following cache variables may also be set: + +``XDG_basedir_INCLUDE_DIR`` + The directory containing ``xdg-basedir.h``. +``XDG_basedir_LIBRARY`` + The path to the xdg-basedir library. + +#]=======================================================================] + +find_package(PkgConfig QUIET) +pkg_check_modules(PC_XDG_basedir QUIET libxdg-basedir) + +find_path(XDG_basedir_INCLUDE_DIR + NAMES basedir.h + PATHS ${PC_XDG_basedir_INCLUDE_DIRS} +) + +find_library(XDG_basedir_LIBRARY + NAMES xdg-basedir + PATHS ${PC_XDG_basedir_LIBRARY_DIRS} +) + +set(XDG_basedir_VERSION ${PC_XDG_basedir_VERSION}) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(XDG_basedir + FOUND_VAR XDG_basedir_FOUND + REQUIRED_VARS + XDG_basedir_LIBRARY + XDG_basedir_INCLUDE_DIR + VERSION_VAR XDG_basedir_VERSION +) + +if (XDG_basedir_FOUND) + set(XDG_basedir_LIBRARIES ${XDG_basedir_LIBRARY}) + set(XDG_basedir_INCLUDE_DIRS ${XDG_basedir_INCLUDE_DIR}) +endif () + +mark_as_advanced( + XDG_basedir_INCLUDE_DIR + XDG_basedir_LIBRARY +) diff --git a/cmake/FindXaudio2.cmake b/cmake/FindXaudio2.cmake new file mode 100644 index 0000000000..065e2d3589 --- /dev/null +++ b/cmake/FindXaudio2.cmake @@ -0,0 +1,18 @@ +# Autodetect if xaudio2 can be used. + +include(CheckCXXSourceCompiles) +set(CMAKE_REQUIRED_FLAGS "") + +check_cxx_source_compiles(" + #include + + #undef NTDDI_VERSION + #undef _WIN32_WINNT + + #define NTDDI_VERSION NTDDI_WIN8 + #define _WIN32_WINNT _WIN32_WINNT_WIN8 + + #include + int main() { return 0; }" + XAUDIO2_FOUND +) diff --git a/cmake/LinkPackage.cmake b/cmake/LinkPackage.cmake new file mode 100644 index 0000000000..f64ccfd51f --- /dev/null +++ b/cmake/LinkPackage.cmake @@ -0,0 +1,18 @@ +function(link_package NAME) + cmake_parse_arguments(LP "ENCOURAGED" "TARGET" "" ${ARGN}) + + if (${NAME}_FOUND) + string(TOUPPER "${NAME}" UCNAME) + add_definitions(-DWITH_${UCNAME}) + if (LP_TARGET AND TARGET ${LP_TARGET}) + target_link_libraries(openttd ${LP_TARGET}) + message(STATUS "${NAME} found -- -DWITH_${UCNAME} -- ${LP_TARGET}") + else() + include_directories(${${NAME}_INCLUDE_DIRS} ${${NAME}_INCLUDE_DIR}) + target_link_libraries(openttd ${${NAME}_LIBRARIES} ${${NAME}_LIBRARY}) + message(STATUS "${NAME} found -- -DWITH_${UCNAME} -- ${${NAME}_INCLUDE_DIRS} ${${NAME}_INCLUDE_DIR} -- ${${NAME}_LIBRARIES} ${${NAME}_LIBRARY}") + endif() + elseif (LP_ENCOURAGED) + message(WARNING "${NAME} not found; compiling OpenTTD without ${NAME} is strongly disencouraged") + endif() +endfunction() diff --git a/cmake/Options.cmake b/cmake/Options.cmake new file mode 100644 index 0000000000..b292567f04 --- /dev/null +++ b/cmake/Options.cmake @@ -0,0 +1,84 @@ +# Set the options for the directories (personal, shared, global). +# +# set_directory_options() +# +function(set_directory_options) + if (APPLE) + set(DEFAULT_PERSONAL_DIR "Documents/OpenTTD") + set(DEFAULT_SHARED_DIR "/Library/Application Support/OpenTTD") + set(DEFAULT_GLOBAL_DIR "(not set)") + elseif (WIN32) + set(DEFAULT_PERSONAL_DIR "OpenTTD") + set(DEFAULT_SHARED_DIR "(not set)") + set(DEFAULT_GLOBAL_DIR "(not set)") + elseif (UNIX) + set(DEFAULT_PERSONAL_DIR ".openttd") + set(DEFAULT_SHARED_DIR "(not set)") + set(DEFAULT_GLOBAL_DIR "${CMAKE_INSTALL_PREFIX}/share/games/openttd") + else () + message(FATAL_ERROR "Unknown OS found; please consider creating a Pull Request to add support for this OS.") + endif () + + if (NOT PERSONAL_DIR) + set(PERSONAL_DIR "${DEFAULT_PERSONAL_DIR}" CACHE STRING "Personal directory") + message(STATUS "Detecting Personal Data directory - ${PERSONAL_DIR}") + endif (NOT PERSONAL_DIR) + + if (NOT SHARED_DIR) + set(SHARED_DIR "${DEFAULT_SHARED_DIR}" CACHE STRING "Shared directory") + message(STATUS "Detecting Shared Data directory - ${SHARED_DIR}") + endif (NOT SHARED_DIR) + + if (NOT GLOBAL_DIR) + set(GLOBAL_DIR "${DEFAULT_GLOBAL_DIR}" CACHE STRING "Global directory") + message(STATUS "Detecting Global Data directory - ${GLOBAL_DIR}") + endif (NOT GLOBAL_DIR) +endfunction() + +# Set some generic options that influence what is being build. +# +# set_options() +# +function(set_options) + if (UNIX AND NOT APPLE) + set(DEFAULT_OPTION_INSTALL_FHS YES) + else (UNIX AND NOT APPLE) + set(DEFAULT_OPTION_INSTALL_FHS NO) + endif (UNIX AND NOT APPLE) + + option(OPTION_DEDICATED "Build dedicated server only (no GUI)" NO) + option(OPTION_INSTALL_FHS "Install with Filesstem Hierarchy Standard folders" ${DEFAULT_OPTION_INSTALL_FHS}) + option(OPTION_USE_ASSERTS "Use assertions; leave enabled for nightlies, betas, and RCs" YES) + option(OPTION_USE_THREADS "Use threads" YES) +endfunction() + +# Show the values of the generic options. +# +# show_options() +# +function(show_options) + message(STATUS "Option Dedicated - ${OPTION_DEDICATED}") + message(STATUS "Option Install FHS - ${OPTION_INSTALL_FHS}") + message(STATUS "Option Use assert - ${OPTION_USE_ASSERTS}") + message(STATUS "Option Use threads - ${OPTION_USE_THREADS}") +endfunction() + +# Add the definitions for the options that are selected. +# +# add_definitions_based_on_options() +# +function(add_definitions_based_on_options) + if (OPTION_DEDICATED) + add_definitions(-DDEDICATED) + endif (OPTION_DEDICATED) + + if (NOT OPTION_USE_THREADS) + add_definitions(-DNO_THREADS) + endif (NOT OPTION_USE_THREADS) + + if (OPTION_USE_ASSERTS) + add_definitions(-DWITH_ASSERT) + else (OPTION_USE_ASSERTS) + add_definitions(-DNDEBUG) + endif (OPTION_USE_ASSERTS) +endfunction() diff --git a/cmake/SourceList.cmake b/cmake/SourceList.cmake new file mode 100644 index 0000000000..6300a19a43 --- /dev/null +++ b/cmake/SourceList.cmake @@ -0,0 +1,63 @@ +# Add a file to be compiled. +# +# add_files([file1 ...] CONDITION condition [condition ...]) +# +# CONDITION is a complete statement that can be evaluated with if(). +# If it evaluates true, the source files will be added; otherwise not. +# For example: ADD_IF SDL_FOUND AND Allegro_FOUND +# +function(add_files) + cmake_parse_arguments(PARAM "" "" "CONDITION" ${ARGN}) + set(PARAM_FILES "${PARAM_UNPARSED_ARGUMENTS}") + + if (PARAM_CONDITION) + if (NOT (${PARAM_CONDITION})) + return() + endif (NOT (${PARAM_CONDITION})) + endif (PARAM_CONDITION) + + foreach(FILE IN LISTS PARAM_FILES) + target_sources(openttd PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/${FILE}) + endforeach() +endfunction(add_files) + +# This function works around an 'issue' with CMake, where +# set_source_files_properties() only works in the scope of the file. We want +# to set properties for the source file on a more global level. To solve this, +# this function records the flags you want, and a macro adds them in the root +# CMakeLists.txt. +# See this URL for more information on the issue: +# http://cmake.3232098.n2.nabble.com/scope-of-set-source-files-properties-td4766111.html +# +# set_compile_flags([file1 ...] COMPILE_FLAGS cflag [cflag ...]) +# +function(set_compile_flags) + cmake_parse_arguments(PARAM "" "" "COMPILE_FLAGS" ${ARGN}) + set(PARAM_FILES "${PARAM_UNPARSED_ARGUMENTS}") + + get_property(SOURCE_PROPERTIES GLOBAL PROPERTY source_properties) + + foreach(FILE IN LISTS PARAM_FILES) + list(APPEND SOURCE_PROPERTIES "${CMAKE_CURRENT_SOURCE_DIR}/${FILE}::${PARAM_COMPILE_FLAGS}") + endforeach() + + set_property(GLOBAL PROPERTY source_properties "${SOURCE_PROPERTIES}") +endfunction(set_compile_flags) + +# Call this macro in the same CMakeLists.txt and after add_executable(). +# This makes sure all the COMPILE_FLAGS of set_compile_flags() are set +# correctly. +# +# process_compile_flags() +# +function(process_compile_flags) + get_property(SOURCE_PROPERTIES GLOBAL PROPERTY source_properties) + + foreach(ENTRY ${SOURCE_PROPERTIES}) + string(REPLACE "::" ";" ENTRY "${ENTRY}") + list(GET ENTRY 0 FILE) + list(GET ENTRY 1 PROPERTIES) + + set_source_files_properties(${FILE} PROPERTIES COMPILE_FLAGS ${PROPERTIES}) + endforeach() +endfunction(process_compile_flags) diff --git a/cmake/Static.cmake b/cmake/Static.cmake new file mode 100644 index 0000000000..7648d05e7f --- /dev/null +++ b/cmake/Static.cmake @@ -0,0 +1,14 @@ +# Set static linking if the platform requires it. +# +# set_static() +# +function(set_static_if_needed) + if (MINGW) + # Let exectutables run outside MinGW environment + # Force searching static libs + set(CMAKE_FIND_LIBRARY_SUFFIXES ".a" PARENT_SCOPE) + + # Force static linking + link_libraries(-static -static-libgcc -static-libstdc++) + endif() +endfunction() diff --git a/cmake/scripts/FindVersion.cmake b/cmake/scripts/FindVersion.cmake new file mode 100644 index 0000000000..5edabeb195 --- /dev/null +++ b/cmake/scripts/FindVersion.cmake @@ -0,0 +1,134 @@ +cmake_minimum_required(VERSION 3.5) + +# +# Finds the current version of the current folder. +# + +find_package(Git QUIET) +# ${CMAKE_SOURCE_DIR}/.git may be a directory or a regular file +if (GIT_FOUND AND EXISTS "${CMAKE_SOURCE_DIR}/.git") + # Make sure LC_ALL is set to something desirable + set(SAVED_LC_ALL "$ENV{LC_ALL}") + set(ENV{LC_ALL} C) + + # Assume the dir is not modified + set(REV_MODIFIED 0) + + # Refresh the index to make sure file stat info is in sync, then look for modifications + execute_process(COMMAND ${GIT_EXECUTABLE} update-index --refresh + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_QUIET + ) + + # See if git tree is modified + execute_process(COMMAND ${GIT_EXECUTABLE} diff-index HEAD + OUTPUT_VARIABLE IS_MODIFIED + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + if (NOT IS_MODIFIED STREQUAL "") + set(REV_MODIFIED 2) + endif() + + # Get last commit hash + execute_process(COMMAND ${GIT_EXECUTABLE} rev-parse --verify HEAD + OUTPUT_VARIABLE FULLHASH + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ERROR_QUIET + ) + set(REV_HASH "${FULLHASH}") + + string(SUBSTRING "${FULLHASH}" 0 10 SHORTHASH) + + # Get the last commit date + execute_process(COMMAND ${GIT_EXECUTABLE} show -s --pretty=format:%ci HEAD + OUTPUT_VARIABLE COMMITDATE + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ) + string(REGEX REPLACE "([0-9]+)-([0-9]+)-([0-9]+).*" "\\1\\2\\3" COMMITDATE "${COMMITDATE}") + set(REV_ISODATE "${COMMITDATE}") + string(SUBSTRING REV_ISODATE 1 4 REV_YEAR) + + # Get the branch + execute_process(COMMAND ${GIT_EXECUTABLE} symbolic-ref -q HEAD + OUTPUT_VARIABLE BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ERROR_QUIET + ) + string(REGEX REPLACE ".*/" "" BRANCH "${BRANCH}") + + # Get the tag + execute_process(COMMAND ${GIT_EXECUTABLE} name-rev --name-only --tags --no-undefined HEAD + OUTPUT_VARIABLE TAG + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + ERROR_QUIET + ) + string(REGEX REPLACE "\^0$" "" TAG "${TAG}") + + if (REV_MODIFIED EQUAL 0) + set(HASHPREFIX "-g") + elseif (REV_MODIFIED EQUAL 2) + set(HASHPREFIX "-m") + else () + set(HASHPREFIX "-u") + endif() + + # Set the version string + if (NOT TAG STREQUAL "") + set(REV_VERSION "${TAG}") + set(REV_ISTAG 1) + + string(REGEX REPLACE "^[0-9.]*$" "" STABLETAG "${TAG}") + if (NOT STABLETAG STREQUAL "") + set(REV_ISSTABLETAG 1) + else () + set(REV_ISSTABLETAG 0) + endif () + else () + set(REV_VERSION "${REV_ISODATE}-${BRANCH}${HASHPREFIX}${SHORTHASH}") + set(REV_ISTAG 0) + set(REV_ISSTABLETAG 0) + endif () + + # Restore LC_ALL + set(ENV{LC_ALL} "${SAVED_LC_ALL}") +elseif (EXISTS "${CMAKE_SOURCE_DIR}/.ottdrev") + file(READ "${CMAKE_SOURCE_DIR}/.ottdrev" OTTDREV) + string(REPLACE "\t" ";" OTTDREV "${OTTDREV}") + list(GET OTTDREV 0 REV_VERSION) + list(GET OTTDREV 1 REV_ISODATE) + list(GET OTTDREV 2 REV_MODIFIED) + list(GET OTTDREV 3 REV_HASH) + list(GET OTTDREV 4 REV_ISTAG) + list(GET OTTDREV 5 REV_ISSTABLETAG) + list(GET OTTDREV 6 REV_YEAR) +else () + message(WARNING "No version detected; this build will NOT be network compatible") + set(REV_VERSION "norev0000") + set(REV_ISODATE "19700101") + set(REV_MODIFIED 1) + set(REV_HASH "unknown") + set(REV_ISTAG 0) + set(REV_ISSTABLETAG 0) + set(REV_YEAR "1970") +endif () + +message(STATUS "Version string: ${REV_VERSION}") + +message(STATUS "Generating rev.cpp") +configure_file("${CMAKE_SOURCE_DIR}/src/rev.cpp.in" + "${FIND_VERSION_BINARY_DIR}/rev.cpp") + +if (WIN32) + message(STATUS "Generating ottdres.rc") + configure_file("${CMAKE_SOURCE_DIR}/src/os/windows/ottdres.rc.in" + "${FIND_VERSION_BINARY_DIR}/ottdres.rc") +endif (WIN32) + +message(STATUS "Generating CPackProperties.cmake") +configure_file("${CMAKE_SOURCE_DIR}/CPackProperties.cmake.in" + "${CPACK_BINARY_DIR}/CPackProperties.cmake" @ONLY) diff --git a/media/baseset/CMakeLists.txt b/media/baseset/CMakeLists.txt index 309ac7a498..c3fe34ce4e 100644 --- a/media/baseset/CMakeLists.txt +++ b/media/baseset/CMakeLists.txt @@ -20,13 +20,13 @@ set(BASESET_OTHER_SOURCE_FILES ) # Done by the subdirectories, if nforenum / grfcodec is installed -if (NFORENUM_FOUND AND GRFCODEC_FOUND) +if (GRFCODEC_FOUND) set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/openttd.grf PROPERTIES GENERATED TRUE) set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/orig_extra.grf PROPERTIES GENERATED TRUE) list(APPEND BASESET_BINARY_FILES openttd.grf) list(APPEND BASESET_BINARY_FILES orig_extra.grf) -endif (NFORENUM_FOUND AND GRFCODEC_FOUND) +endif (GRFCODEC_FOUND) set(BASESET_EXTRAGRF_FILE ${CMAKE_CURRENT_SOURCE_DIR}/orig_extra.grf) diff --git a/media/baseset/openttd/CMakeLists.txt b/media/baseset/openttd/CMakeLists.txt index 42d62dd7cc..c4f8d61ade 100644 --- a/media/baseset/openttd/CMakeLists.txt +++ b/media/baseset/openttd/CMakeLists.txt @@ -3,7 +3,7 @@ # This is mainly because not many people have both of these tools installed, # so it is cheaper to cache them in git, and only regenerate when you are # working on it / have the tools installed. -if (NFORENUM_FOUND AND GRFCODEC_FOUND) - include(CreateGrfCommand REQUIRED) +if (GRFCODEC_FOUND) + include(CreateGrfCommand) create_grf_command() -endif (NFORENUM_FOUND AND GRFCODEC_FOUND) +endif (GRFCODEC_FOUND) diff --git a/media/baseset/orig_extra/CMakeLists.txt b/media/baseset/orig_extra/CMakeLists.txt index f865a8dd0d..36a25329f5 100644 --- a/media/baseset/orig_extra/CMakeLists.txt +++ b/media/baseset/orig_extra/CMakeLists.txt @@ -3,12 +3,12 @@ # This is mainly because not many people have both of these tools installed, # so it is cheaper to cache them in git, and only regenerate when you are # working on it / have the tools installed. -if (NFORENUM_FOUND AND GRFCODEC_FOUND) - include(CreateGrfCommand REQUIRED) +if (GRFCODEC_FOUND) + include(CreateGrfCommand) create_grf_command( # We share some files with 'openttd' grf ${CMAKE_CURRENT_SOURCE_DIR}/../openttd/airports.png ${CMAKE_CURRENT_SOURCE_DIR}/../openttd/canals.png ${CMAKE_CURRENT_SOURCE_DIR}/../openttd/chars.png ) -endif (NFORENUM_FOUND AND GRFCODEC_FOUND) +endif (GRFCODEC_FOUND) diff --git a/os/windows/openttd.manifest b/os/windows/openttd.manifest new file mode 100644 index 0000000000..ee1c7ea224 --- /dev/null +++ b/os/windows/openttd.manifest @@ -0,0 +1,29 @@ + + + + + + + + + + + + True/PM + + + + + + + + + + + + + + + + + diff --git a/src/3rdparty/CMakeLists.txt b/src/3rdparty/CMakeLists.txt new file mode 100644 index 0000000000..e3927fa217 --- /dev/null +++ b/src/3rdparty/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(md5) +add_subdirectory(squirrel) +add_subdirectory(os2) diff --git a/src/3rdparty/md5/CMakeLists.txt b/src/3rdparty/md5/CMakeLists.txt new file mode 100644 index 0000000000..58720ca2d6 --- /dev/null +++ b/src/3rdparty/md5/CMakeLists.txt @@ -0,0 +1,4 @@ +add_files( + md5.cpp + md5.h +) diff --git a/src/3rdparty/os2/CMakeLists.txt b/src/3rdparty/os2/CMakeLists.txt new file mode 100644 index 0000000000..8edc63479e --- /dev/null +++ b/src/3rdparty/os2/CMakeLists.txt @@ -0,0 +1,7 @@ +add_files( + getaddrinfo.c + getaddrinfo.h + getnameinfo.c + getnameinfo.h + CONDITION OPTION_OS2 +) diff --git a/src/3rdparty/squirrel/CMakeLists.txt b/src/3rdparty/squirrel/CMakeLists.txt new file mode 100644 index 0000000000..9602087cdf --- /dev/null +++ b/src/3rdparty/squirrel/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory(include) +add_subdirectory(sqstdlib) +add_subdirectory(squirrel) diff --git a/src/3rdparty/squirrel/include/CMakeLists.txt b/src/3rdparty/squirrel/include/CMakeLists.txt new file mode 100644 index 0000000000..5237360d31 --- /dev/null +++ b/src/3rdparty/squirrel/include/CMakeLists.txt @@ -0,0 +1,6 @@ +add_files( + sqstdaux.h + sqstdmath.h + sqstdstring.h + squirrel.h +) diff --git a/src/3rdparty/squirrel/sqstdlib/CMakeLists.txt b/src/3rdparty/squirrel/sqstdlib/CMakeLists.txt new file mode 100644 index 0000000000..2b3bd6bb31 --- /dev/null +++ b/src/3rdparty/squirrel/sqstdlib/CMakeLists.txt @@ -0,0 +1,4 @@ +add_files( + sqstdaux.cpp + sqstdmath.cpp +) diff --git a/src/3rdparty/squirrel/squirrel/CMakeLists.txt b/src/3rdparty/squirrel/squirrel/CMakeLists.txt new file mode 100644 index 0000000000..a86a92b7dd --- /dev/null +++ b/src/3rdparty/squirrel/squirrel/CMakeLists.txt @@ -0,0 +1,30 @@ +add_files( + sqapi.cpp + sqarray.h + sqbaselib.cpp + sqclass.cpp + sqclass.h + sqclosure.h + sqcompiler.cpp + sqcompiler.h + sqdebug.cpp + sqfuncproto.h + sqfuncstate.cpp + sqfuncstate.h + sqlexer.cpp + sqlexer.h + sqmem.cpp + sqobject.cpp + sqobject.h + sqopcodes.h + sqpcheader.h + sqstate.cpp + sqstate.h + sqstring.h + sqtable.cpp + sqtable.h + squserdata.h + squtils.h + sqvm.cpp + sqvm.h +) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000..0ccf650abf --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,479 @@ +add_subdirectory(3rdparty) +add_subdirectory(ai) +add_subdirectory(blitter) +add_subdirectory(core) +add_subdirectory(game) +add_subdirectory(lang) +add_subdirectory(linkgraph) +add_subdirectory(misc) +add_subdirectory(music) +add_subdirectory(network) +add_subdirectory(os) +add_subdirectory(pathfinder) +add_subdirectory(saveload) +add_subdirectory(script) +add_subdirectory(settingsgen) +add_subdirectory(sound) +add_subdirectory(spriteloader) +add_subdirectory(strgen) +add_subdirectory(table) +add_subdirectory(video) +add_subdirectory(widgets) + +add_files( + viewport_sprite_sorter_sse4.cpp + CONDITION SSE_FOUND +) +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + set_compile_flags( + viewport_sprite_sorter_sse4.cpp + COMPILE_FLAGS -msse4.1) +endif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + +add_files( + aircraft.h + aircraft_cmd.cpp + aircraft_gui.cpp + airport.cpp + airport.h + airport_gui.cpp + animated_tile.cpp + animated_tile_func.h + articulated_vehicles.cpp + articulated_vehicles.h + autoreplace.cpp + autoreplace_base.h + autoreplace_cmd.cpp + autoreplace_func.h + autoreplace_gui.cpp + autoreplace_gui.h + autoreplace_type.h + autoslope.h + base_consist.cpp + base_consist.h + base_media_base.h + base_media_func.h + base_station_base.h + bitmap_type.h + bmp.cpp + bmp.h + bootstrap_gui.cpp + bridge.h + bridge_gui.cpp + bridge_map.cpp + bridge_map.h + build_vehicle_gui.cpp + cargo_type.h + cargoaction.cpp + cargoaction.h + cargomonitor.cpp + cargomonitor.h + cargopacket.cpp + cargopacket.h + cargotype.cpp + cargotype.h + cheat.cpp + cheat_func.h + cheat_gui.cpp + cheat_type.h + clear_cmd.cpp + clear_func.h + clear_map.h + cmd_helper.h + command.cpp + command_func.h + command_type.h + company_base.h + company_cmd.cpp + company_func.h + company_gui.cpp + company_gui.h + company_manager_face.h + company_type.h + console.cpp + console_cmds.cpp + console_func.h + console_gui.cpp + console_gui.h + console_internal.h + console_type.h + cpu.cpp + cpu.h + crashlog.cpp + crashlog.h + currency.cpp + currency.h + date.cpp + date_func.h + date_gui.cpp + date_gui.h + date_type.h + debug.cpp + debug.h + dedicated.cpp + depot.cpp + depot_base.h + depot_cmd.cpp + depot_func.h + depot_gui.cpp + depot_map.h + depot_type.h + direction_func.h + direction_type.h + disaster_vehicle.cpp + disaster_vehicle.h + dock_gui.cpp + driver.cpp + driver.h + economy.cpp + economy_base.h + economy_func.h + economy_type.h + effectvehicle.cpp + effectvehicle_base.h + effectvehicle_func.h + elrail.cpp + elrail_func.h + engine.cpp + engine_base.h + engine_func.h + engine_gui.cpp + engine_gui.h + engine_type.h + error.h + error_gui.cpp + fileio.cpp + fileio_func.h + fileio_type.h + fios.cpp + fios.h + fios_gui.cpp + fontcache.cpp + fontcache.h + fontdetection.cpp + fontdetection.h + framerate_gui.cpp + framerate_type.h + gamelog.cpp + gamelog.h + gamelog_internal.h + genworld.cpp + genworld.h + genworld_gui.cpp + gfx.cpp + gfx_func.h + gfx_layout.cpp + gfx_layout.h + gfx_type.h + gfxinit.cpp + gfxinit.h + goal.cpp + goal_base.h + goal_gui.cpp + goal_type.h + graph_gui.cpp + graph_gui.h + ground_vehicle.cpp + ground_vehicle.hpp + group.h + group_cmd.cpp + group_gui.cpp + group_gui.h + group_type.h + gui.h + guitimer_func.h + heightmap.cpp + heightmap.h + highscore.cpp + highscore.h + highscore_gui.cpp + hotkeys.cpp + hotkeys.h + house.h + house_type.h + industry.h + industry_cmd.cpp + industry_gui.cpp + industry_map.h + industry_type.h + industrytype.h + ini.cpp + ini_load.cpp + ini_type.h + intro_gui.cpp + landscape.cpp + landscape.h + landscape_type.h + language.h + livery.h + main_gui.cpp + map.cpp + map_func.h + map_type.h + misc.cpp + misc_cmd.cpp + misc_gui.cpp + mixer.cpp + mixer.h + music.cpp + music_gui.cpp + newgrf.cpp + newgrf.h + newgrf_airport.cpp + newgrf_airport.h + newgrf_airporttiles.cpp + newgrf_airporttiles.h + newgrf_animation_base.h + newgrf_animation_type.h + newgrf_callbacks.h + newgrf_canal.cpp + newgrf_canal.h + newgrf_cargo.cpp + newgrf_cargo.h + newgrf_class.h + newgrf_class_func.h + newgrf_commons.cpp + newgrf_commons.h + newgrf_config.cpp + newgrf_config.h + newgrf_debug.h + newgrf_debug_gui.cpp + newgrf_engine.cpp + newgrf_engine.h + newgrf_generic.cpp + newgrf_generic.h + newgrf_gui.cpp + newgrf_house.cpp + newgrf_house.h + newgrf_industries.cpp + newgrf_industries.h + newgrf_industrytiles.cpp + newgrf_industrytiles.h + newgrf_object.cpp + newgrf_object.h + newgrf_profiling.cpp + newgrf_profiling.h + newgrf_properties.h + newgrf_railtype.cpp + newgrf_railtype.h + newgrf_roadtype.cpp + newgrf_roadtype.h + newgrf_sound.cpp + newgrf_sound.h + newgrf_spritegroup.cpp + newgrf_spritegroup.h + newgrf_station.cpp + newgrf_station.h + newgrf_storage.cpp + newgrf_storage.h + newgrf_text.cpp + newgrf_text.h + newgrf_town.cpp + newgrf_town.h + newgrf_townname.cpp + newgrf_townname.h + news_func.h + news_gui.cpp + news_gui.h + news_type.h + object.h + object_base.h + object_cmd.cpp + object_gui.cpp + object_map.h + object_type.h + openttd.cpp + openttd.h + order_backup.cpp + order_backup.h + order_base.h + order_cmd.cpp + order_func.h + order_gui.cpp + order_type.h + osk_gui.cpp + pbs.cpp + pbs.h + progress.cpp + progress.h + querystring_gui.h + rail.cpp + rail.h + rail_cmd.cpp + rail_gui.cpp + rail_gui.h + rail_map.h + rail_type.h + rev.h + road.cpp + road.h + road_cmd.cpp + road_cmd.h + road_func.h + road_gui.cpp + road_gui.h + road_internal.h + road_map.cpp + road_map.h + road_type.h + roadstop.cpp + roadstop_base.h + roadveh.h + roadveh_cmd.cpp + roadveh_gui.cpp + safeguards.h + screenshot_gui.cpp + screenshot_gui.h + screenshot.cpp + screenshot.h + settings.cpp + settings_func.h + settings_gui.cpp + settings_gui.h + settings_internal.h + settings_type.h + ship.h + ship_cmd.cpp + ship_gui.cpp + signal.cpp + signal_func.h + signal_type.h + signs.cpp + signs_base.h + signs_cmd.cpp + signs_func.h + signs_gui.cpp + signs_type.h + slope_func.h + slope_type.h + smallmap_gui.cpp + smallmap_gui.h + sortlist_type.h + sound.cpp + sound_func.h + sound_type.h + sprite.cpp + sprite.h + spritecache.cpp + spritecache.h + station.cpp + station_base.h + station_cmd.cpp + station_func.h + station_gui.cpp + station_gui.h + station_kdtree.h + station_map.h + station_type.h + statusbar_gui.cpp + statusbar_gui.h + stdafx.h + story.cpp + story_base.h + story_gui.cpp + story_type.h + strgen/strgen.h + string.cpp + string_base.h + string_func.h + string_type.h + stringfilter.cpp + stringfilter_type.h + strings.cpp + strings_func.h + strings_type.h + subsidy.cpp + subsidy_base.h + subsidy_func.h + subsidy_gui.cpp + subsidy_type.h + tar_type.h + terraform_cmd.cpp + terraform_gui.cpp + terraform_gui.h + textbuf.cpp + textbuf_gui.h + textbuf_type.h + texteff.cpp + texteff.hpp + textfile_gui.cpp + textfile_gui.h + textfile_type.h + tgp.cpp + tgp.h + thread.h + tile_cmd.h + tile_map.cpp + tile_map.h + tile_type.h + tilearea.cpp + tilearea_type.h + tilehighlight_func.h + tilehighlight_type.h + tilematrix_type.hpp + timetable.h + timetable_cmd.cpp + timetable_gui.cpp + toolbar_gui.cpp + toolbar_gui.h + town.h + town_cmd.cpp + town_gui.cpp + town_kdtree.h + town_map.h + town_type.h + townname.cpp + townname_func.h + townname_type.h + track_func.h + track_type.h + train.h + train_cmd.cpp + train_gui.cpp + transparency.h + transparency_gui.cpp + transparency_gui.h + transport_type.h + tree_cmd.cpp + tree_gui.cpp + tree_map.h + tunnel_map.cpp + tunnel_map.h + tunnelbridge.h + tunnelbridge_cmd.cpp + tunnelbridge_map.h + vehicle.cpp + vehicle_base.h + vehicle_cmd.cpp + vehicle_func.h + vehicle_gui.cpp + vehicle_gui.h + vehicle_gui_base.h + vehicle_type.h + vehiclelist.cpp + vehiclelist.h + viewport.cpp + viewport_func.h + viewport_gui.cpp + viewport_kdtree.h + viewport_sprite_sorter.h + viewport_type.h + void_cmd.cpp + void_map.h + water.h + water_cmd.cpp + water_map.h + waypoint.cpp + waypoint_base.h + waypoint_cmd.cpp + waypoint_func.h + waypoint_gui.cpp + widget.cpp + widget_type.h + window.cpp + window_func.h + window_gui.h + window_type.h + zoom_func.h + zoom_type.h +) diff --git a/src/ai/CMakeLists.txt b/src/ai/CMakeLists.txt new file mode 100644 index 0000000000..cab886b265 --- /dev/null +++ b/src/ai/CMakeLists.txt @@ -0,0 +1,14 @@ +add_files( + ai.hpp + ai_config.cpp + ai_config.hpp + ai_core.cpp + ai_gui.cpp + ai_gui.hpp + ai_info.cpp + ai_info.hpp + ai_instance.cpp + ai_instance.hpp + ai_scanner.cpp + ai_scanner.hpp +) diff --git a/src/blitter/CMakeLists.txt b/src/blitter/CMakeLists.txt new file mode 100644 index 0000000000..2abe6aec0e --- /dev/null +++ b/src/blitter/CMakeLists.txt @@ -0,0 +1,55 @@ +add_files( + 32bpp_anim.cpp + 32bpp_anim.hpp + 32bpp_base.cpp + 32bpp_base.hpp + 32bpp_optimized.cpp + 32bpp_optimized.hpp + 32bpp_simple.cpp + 32bpp_simple.hpp + 8bpp_base.cpp + 8bpp_base.hpp + 8bpp_optimized.cpp + 8bpp_optimized.hpp + 8bpp_simple.cpp + 8bpp_simple.hpp + CONDITION NOT OPTION_DEDICATED +) + +add_files( + 32bpp_anim_sse2.cpp + 32bpp_anim_sse2.hpp + 32bpp_anim_sse4.cpp + 32bpp_anim_sse4.hpp + 32bpp_sse2.cpp + 32bpp_sse2.hpp + 32bpp_sse4.cpp + 32bpp_sse4.hpp + 32bpp_sse_func.hpp + 32bpp_sse_type.h + 32bpp_ssse3.cpp + 32bpp_ssse3.hpp + CONDITION NOT OPTION_DEDICATED AND SSE_FOUND +) + +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + set_compile_flags( + 32bpp_anim_sse2.cpp + 32bpp_sse2.cpp + COMPILE_FLAGS -msse2) + set_compile_flags( + 32bpp_ssse3.cpp + COMPILE_FLAGS -mssse3) + set_compile_flags( + 32bpp_anim_sse4.cpp + 32bpp_sse4.cpp + COMPILE_FLAGS -msse4.1) +endif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang") + +add_files( + base.hpp + common.hpp + factory.hpp + null.cpp + null.hpp +) diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt new file mode 100644 index 0000000000..96da089326 --- /dev/null +++ b/src/core/CMakeLists.txt @@ -0,0 +1,30 @@ +add_files( + alloc_func.cpp + alloc_func.hpp + alloc_type.hpp + backup_type.hpp + bitmath_func.cpp + bitmath_func.hpp + endian_func.hpp + endian_type.hpp + enum_type.hpp + geometry_func.cpp + geometry_func.hpp + geometry_type.hpp + kdtree.hpp + math_func.cpp + math_func.hpp + mem_func.hpp + multimap.hpp + overflowsafe_type.hpp + pool_func.cpp + pool_func.hpp + pool_type.hpp + random_func.cpp + random_func.hpp + smallmap_type.hpp + smallmatrix_type.hpp + smallstack_type.hpp + smallvec_type.hpp + string_compare_type.hpp +) diff --git a/src/core/endian_type.hpp b/src/core/endian_type.hpp index 1b927ef45a..e1add251ed 100644 --- a/src/core/endian_type.hpp +++ b/src/core/endian_type.hpp @@ -23,30 +23,8 @@ /** Big endian builds use this for TTD_ENDIAN. */ #define TTD_BIG_ENDIAN 1 -/* Windows has always LITTLE_ENDIAN */ -#if defined(_WIN32) || defined(__OS2__) || defined(__HAIKU__) -# define TTD_ENDIAN TTD_LITTLE_ENDIAN -#elif defined(OSX) -# include -# if __DARWIN_BYTE_ORDER == __DARWIN_LITTLE_ENDIAN -# define TTD_ENDIAN TTD_LITTLE_ENDIAN -# else -# define TTD_ENDIAN TTD_BIG_ENDIAN -# endif -#elif defined(__OpenBSD__) -# include -# if BYTE_ORDER == LITTLE_ENDIAN -# define TTD_ENDIAN TTD_LITTLE_ENDIAN -# else -# define TTD_ENDIAN TTD_BIG_ENDIAN -# endif -#elif !defined(TESTING) -# include -# if __BYTE_ORDER == __LITTLE_ENDIAN -# define TTD_ENDIAN TTD_LITTLE_ENDIAN -# else -# define TTD_ENDIAN TTD_BIG_ENDIAN -# endif -#endif /* _WIN32 || __OS2__ */ +#if !defined(TTD_ENDIAN) +# error "TTD_ENDIAN is not defined; please set it to either TTD_LITTLE_ENDIAN or TTD_BIG_ENDIAN" +#endif /* !TTD_ENDIAN */ #endif /* ENDIAN_TYPE_HPP */ diff --git a/src/depend/depend.cpp b/src/depend/depend.cpp deleted file mode 100644 index 5a3bd868de..0000000000 --- a/src/depend/depend.cpp +++ /dev/null @@ -1,1084 +0,0 @@ -/* - * This file is part of OpenTTD. - * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. - * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . - */ - -/** - * @file depend/depend.cpp Custom implementation of Makedepend. - * - * We previously used makedepend, but that could not handle the amount of - * files we have and does not handle conditional includes in a sane manner. - * This caused many link problems because not enough files were recompiled. - * This has lead to the development of our own dependency generator. It is - * meant to be a substitute to the (relatively slow) dependency generation - * via gcc. It thus helps speeding up compilation. It will also ignore - * system headers making it less error prone when system headers are moved - * or renamed. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -/** - * Return the length of an fixed size array. - * Unlike sizeof this function returns the number of elements - * of the given type. - * - * @param x The pointer to the first element of the array - * @return The number of elements - */ -#define lengthof(x) (sizeof(x) / sizeof(x[0])) - -/** - * Get the last element of an fixed size array. - * - * @param x The pointer to the first element of the array - * @return The pointer to the last element of the array - */ -#define lastof(x) (&x[lengthof(x) - 1]) - -/** - * Copies characters from one buffer to another. - * - * Copies the source string to the destination buffer with respect of the - * terminating null-character and the last pointer to the last element in - * the destination buffer. If the last pointer is set to nullptr no boundary - * check is performed. - * - * @note usage: strecpy(dst, src, lastof(dst)); - * @note lastof() applies only to fixed size arrays - * - * @param dst The destination buffer - * @param src The buffer containing the string to copy - * @param last The pointer to the last element of the destination buffer - * @return The pointer to the terminating null-character in the destination buffer - */ -char *strecpy(char *dst, const char *src, const char *last) -{ - assert(dst <= last); - while (dst != last && *src != '\0') { - *dst++ = *src++; - } - *dst = '\0'; - - if (dst == last && *src != '\0') { - fprintf(stderr, "String too long for destination buffer\n"); - exit(-3); - } - return dst; -} - -/** - * Appends characters from one string to another. - * - * Appends the source string to the destination string with respect of the - * terminating null-character and and the last pointer to the last element - * in the destination buffer. If the last pointer is set to nullptr no - * boundary check is performed. - * - * @note usage: strecat(dst, src, lastof(dst)); - * @note lastof() applies only to fixed size arrays - * - * @param dst The buffer containing the target string - * @param src The buffer containing the string to append - * @param last The pointer to the last element of the destination buffer - * @return The pointer to the terminating null-character in the destination buffer - */ -static char *strecat(char *dst, const char *src, const char *last) -{ - assert(dst <= last); - while (*dst != '\0') { - if (dst == last) return dst; - dst++; - } - - return strecpy(dst, src, last); -} - -#if defined(__CYGWIN__) -/** - * Version of strdup copied from glibc. - * Duplicate S, returning an identical malloc'd string. - * @param s The string to duplicate. - */ -char * -strdup (const char *s) -{ - size_t len = strlen(s) + 1; - void *n = malloc(len); - - if (n == NULL) return NULL; - return (char *) memcpy(n, s, len); -} -#endif - -/** - * Version of the standard free that accepts const pointers. - * @param ptr The data to free. - */ -static inline void free(const void *ptr) -{ - free(const_cast(ptr)); -} - -#ifndef PATH_MAX -/** The maximum length of paths, if we don't know it. */ -# define PATH_MAX 260 -#endif - -/** Simple string comparator using strcmp as implementation */ -struct StringCompare { - /** - * Compare a to b using strcmp. - * @param a string to compare. - * @param b string to compare. - * @return whether a is less than b. - */ - bool operator () (const char *a, const char *b) const - { - return strcmp(a, b) < 0; - } -}; -/** Set of C-style strings. */ -typedef std::set StringSet; -/** Mapping of C-style string to a set of C-style strings. */ -typedef std::map StringMap; -/** Pair of C-style string and a set of C-style strings. */ -typedef std::pair StringMapItem; - -/** Include directory to search in. */ -static StringSet _include_dirs; -/** Files that have been parsed/handled with their dependencies. */ -static StringMap _files; -/** Dependencies of headers. */ -static StringMap _headers; -/** The current 'active' defines. */ -static StringSet _defines; - -/** - * Helper class to read a file. - */ -class File { -public: - /** - * Create the helper by opening the given file. - * @param filename the file to open - * @post the file is open; otherwise the application is killed. - */ - File(const char *filename) - { - this->fp = fopen(filename, "r"); - if (this->fp == nullptr) { - fprintf(stdout, "Could not open %s for reading\n", filename); - exit(1); - } - this->dirname = strdup(filename); - char *last = strrchr(this->dirname, '/'); - if (last != nullptr) { - *last = '\0'; - } else { - *this->dirname = '\0'; - } - } - - /** Free everything we have allocated. */ - ~File() - { - fclose(this->fp); - free(this->dirname); - } - - /** - * Get a single character from the file. - * If we are reading beyond the end of the file '\0' is returned. - * @return the read character. - */ - char GetChar() const - { - int c = fgetc(this->fp); - return (c == EOF) ? '\0' : c; - } - - /** - * Get the directory name of the file. - * @return the directory name. - */ - const char *GetDirname() const - { - return this->dirname; - } - -private: - FILE *fp; ///< The currently opened file. - char *dirname; ///< The directory of the file. -}; - -/** A token returned by the tokenizer. */ -enum Token { - TOKEN_UNKNOWN, ///< Unknown token - TOKEN_END, ///< End of document - TOKEN_EOL, ///< End of line - TOKEN_SHARP, ///< # character, usually telling something important comes. - TOKEN_LOCAL, ///< Read a local include - TOKEN_GLOBAL, ///< Read a global include - TOKEN_IDENTIFIER, ///< Identifier within the data. - TOKEN_DEFINE, ///< \c \#define in code - TOKEN_IF, ///< \c \#if in code - TOKEN_IFDEF, ///< \c \#ifdef in code - TOKEN_IFNDEF, ///< \c \#ifndef in code - TOKEN_ELIF, ///< \c \#elif in code - TOKEN_ELSE, ///< \c \#else in code - TOKEN_ENDIF, ///< \c \#endif in code - TOKEN_UNDEF, ///< \c \#undef in code - TOKEN_OR, ///< '||' within \c \#if expression - TOKEN_AND, ///< '&&' within \c \#if expression - TOKEN_DEFINED, ///< 'defined' within \c \#if expression - TOKEN_OPEN, ///< '(' within \c \#if expression - TOKEN_CLOSE, ///< ')' within \c \#if expression - TOKEN_NOT, ///< '!' within \c \#if expression - TOKEN_ZERO, ///< '0' within \c \#if expression - TOKEN_INCLUDE, ///< \c \#include in code -}; - -/** Mapping from a C-style keyword representation to a Token. */ -typedef std::map KeywordList; - -/** - * Lexer of a file. - */ -class Lexer { -public: - /** - * Create the lexer and fill the keywords table. - * @param file the file to read from. - */ - Lexer(const File *file) : file(file), current_char('\0'), string(nullptr), token(TOKEN_UNKNOWN) - { - this->keywords["define"] = TOKEN_DEFINE; - this->keywords["defined"] = TOKEN_DEFINED; - this->keywords["if"] = TOKEN_IF; - this->keywords["ifdef"] = TOKEN_IFDEF; - this->keywords["ifndef"] = TOKEN_IFNDEF; - this->keywords["include"] = TOKEN_INCLUDE; - this->keywords["elif"] = TOKEN_ELIF; - this->keywords["else"] = TOKEN_ELSE; - this->keywords["endif"] = TOKEN_ENDIF; - this->keywords["undef"] = TOKEN_UNDEF; - - /* Initialise currently read character. */ - this->Next(); - - /* Allocate the buffer. */ - this->buf_len = 32; - this->buf = (char*)malloc(sizeof(*this->buf) * this->buf_len); - } - - /** Free everything */ - ~Lexer() - { - free(this->buf); - } - - /** - * Read the next character into 'current_char'. - */ - void Next() - { - this->current_char = this->file->GetChar(); - } - - /** - * Get the current token. - * @return the token. - */ - Token GetToken() const - { - return this->token; - } - - /** - * Read the currently processed string. - * @return the string, can be nullptr. - */ - const char *GetString() const - { - return this->string; - } - - /** - * Perform the lexing/tokenizing of the file till we can return something - * that must be parsed. - */ - void Lex() - { - for (;;) { - free(this->string); - this->string = nullptr; - this->token = TOKEN_UNKNOWN; - - switch (this->current_char) { - /* '\0' means End-Of-File */ - case '\0': this->token = TOKEN_END; return; - - /* Skip some chars, as they don't do anything */ - case '\t': this->Next(); break; - case '\r': this->Next(); break; - case ' ': this->Next(); break; - - case '\\': - this->Next(); - if (this->current_char == '\n') this->Next(); - break; - - case '\n': - this->token = TOKEN_EOL; - this->Next(); - return; - - case '#': - this->token = TOKEN_SHARP; - this->Next(); - return; - - case '"': - this->ReadString('"', TOKEN_LOCAL); - this->Next(); - return; - - case '<': - this->ReadString('>', TOKEN_GLOBAL); - this->Next(); - return; - - case '&': - this->Next(); - if (this->current_char == '&') { - this->Next(); - this->token = TOKEN_AND; - return; - } - break; - - case '|': - this->Next(); - if (this->current_char == '|') { - this->Next(); - this->token = TOKEN_OR; - return; - } - break; - - case '(': - this->Next(); - this->token = TOKEN_OPEN; - return; - - case ')': - this->Next(); - this->token = TOKEN_CLOSE; - return; - - case '!': - this->Next(); - if (this->current_char != '=') { - this->token = TOKEN_NOT; - return; - } - break; - - /* Possible begin of comment */ - case '/': - this->Next(); - switch (this->current_char) { - case '*': { - this->Next(); - char previous_char = '\0'; - while ((this->current_char != '/' || previous_char != '*') && this->current_char != '\0') { - previous_char = this->current_char; - this->Next(); - } - this->Next(); - break; - } - case '/': while (this->current_char != '\n' && this->current_char != '\0') this->Next(); break; - default: break; - } - break; - - default: - if (isalpha(this->current_char) || this->current_char == '_') { - /* If the name starts with a letter, it is an identifier */ - this->ReadIdentifier(); - return; - } - if (isdigit(this->current_char)) { - bool zero = this->current_char == '0'; - this->Next(); - if (this->current_char == 'x' || this->current_char == 'X') Next(); - while (isdigit(this->current_char) || this->current_char == '.' || (this->current_char >= 'a' && this->current_char <= 'f') || (this->current_char >= 'A' && this->current_char <= 'F')) { - zero &= this->current_char == '0'; - this->Next(); - } - if (zero) this->token = TOKEN_ZERO; - return; - } - this->Next(); - break; - } - } - } - -private: - /** - * The token based on keyword with a given name. - * @param name the actual keyword. - * @return the token of the keyword. - */ - Token FindKeyword(const char *name) const - { - KeywordList::const_iterator it = this->keywords.find(name); - if (it == this->keywords.end()) return TOKEN_IDENTIFIER; - return (*it).second; - } - - /** - * Read an identifier. - */ - void ReadIdentifier() - { - size_t count = 0; - - /* Read the rest of the identifier */ - do { - this->buf[count++] = this->current_char; - this->Next(); - - if (count >= buf_len) { - /* Scale the buffer if required */ - this->buf_len *= 2; - this->buf = (char *)realloc(this->buf, sizeof(*this->buf) * this->buf_len); - } - } while ((isalpha(this->current_char) || this->current_char == '_' || isdigit(this->current_char))); - this->buf[count] = '\0'; - - free(this->string); - this->string = strdup(this->buf); - this->token = FindKeyword(this->string); - } - - /** - * Read a string up to a given character, then set the given token. - * @param end the 'marker' for the end of the string. - * @param token the token to set after returning. - */ - void ReadString(char end, Token token) - { - size_t count = 0; - this->Next(); - while (this->current_char != end && this->current_char != ')' && this->current_char != '\n' && this->current_char != '\0') { - this->buf[count++] = this->current_char; - this->Next(); - - if (count >= this->buf_len) { - /* Scale the buffer if required */ - this->buf_len *= 2; - this->buf = (char *)realloc(this->buf, sizeof(*this->buf) * this->buf_len); - } - } - this->buf[count] = '\0'; - free(this->string); - this->string = strdup(this->buf); - this->token = token; - } - - const File *file; ///< The file to read from. - char current_char; ///< The current character to process. - char *string; ///< Currently processed string. - Token token; ///< The current token to process. - char *buf; ///< Temporary buffer. - size_t buf_len; ///< Length of the temporary buffer. - KeywordList keywords; ///< All keywords we know of. -}; - -/** - * Generate a path from a directory name and a relative filename. - * If the file is not local the include directory names will be used instead - * of the passed parameter with directory name. If the file is local both will - * be queried where the parameter takes precedence. - * @param dirname the directory to look in. - * @param filename the file to look for. - * @param local whether to look locally (in dirname) for the file. - * @return the absolute path, or nullptr if the file doesn't exist. - */ -const char *GeneratePath(const char *dirname, const char *filename, bool local) -{ - /* Ignore C++ standard library headers. */ - if (strchr(filename, '.') == nullptr) return nullptr; - - if (local) { - if (access(filename, R_OK) == 0) return strdup(filename); - - char path[PATH_MAX]; - strecpy(path, dirname, lastof(path)); - const char *p = filename; - /* Remove '..' from the begin of the filename. */ - while (*p == '.') { - if (*(++p) == '.') { - char *s = strrchr(path, '/'); - if (s != nullptr) *s = '\0'; - p += 2; - } - } - strecat(path, "/", lastof(path)); - strecat(path, p, lastof(path)); - - if (access(path, R_OK) == 0) return strdup(path); - } - - for (StringSet::iterator it = _include_dirs.begin(); it != _include_dirs.end(); it++) { - char path[PATH_MAX]; - strecpy(path, *it, lastof(path)); - const char *p = filename; - /* Remove '..' from the begin of the filename. */ - while (*p == '.') { - if (*(++p) == '.') { - char *s = strrchr(path, '/'); - if (s != nullptr) *s = '\0'; - p += 2; - } - } - strecat(path, "/", lastof(path)); - strecat(path, p, lastof(path)); - - if (access(path, R_OK) == 0) return strdup(path); - } - - return nullptr; -} - -/** - * Try to parse a 'defined(expr)' expression. - * @param lexer the lexer to get tokens from. - * @param defines the set of known defines. - * @param verbose whether to give verbose debugging information. - * @return the value of the expression. - */ -bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose); - -/** - * Try to parse a 'expr || expr' expression. - * @param lexer the lexer to get tokens from. - * @param defines the set of known defines. - * @param verbose whether to give verbose debugging information. - * @return the value of the expression. - */ -bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose); - -/** - * Try to parse a '!expr' expression. Also parses the '(expr)', '0' and - * identifiers. Finally it also consumes any unknown tokens. - * @param lexer the lexer to get tokens from. - * @param defines the set of known defines. - * @param verbose whether to give verbose debugging information. - * @return the value of the expression. - */ -bool ExpressionNot(Lexer *lexer, StringSet *defines, bool verbose) -{ - if (lexer->GetToken() == TOKEN_NOT) { - if (verbose) fprintf(stderr, "!"); - lexer->Lex(); - bool value = !ExpressionDefined(lexer, defines, verbose); - if (verbose) fprintf(stderr, "[%d]", value); - return value; - } - - if (lexer->GetToken() == TOKEN_OPEN) { - if (verbose) fprintf(stderr, "("); - lexer->Lex(); - bool value = ExpressionOr(lexer, defines, verbose); - if (verbose) fprintf(stderr, ")[%d]", value); - lexer->Lex(); - return value; - } - - if (lexer->GetToken() == TOKEN_ZERO) { - if (verbose) fprintf(stderr, "0"); - lexer->Lex(); - if (verbose) fprintf(stderr, "[0]"); - return false; - } - - bool first = true; - while (lexer->GetToken() == TOKEN_UNKNOWN || lexer->GetToken() == TOKEN_IDENTIFIER) { - if (verbose && first) fprintf(stderr, ""); - first = false; - lexer->Lex(); - } - - return true; -} - -/** - * Try to parse a 'defined(expr)' expression. - * @param lexer the lexer to get tokens from. - * @param defines the set of known defines. - * @param verbose whether to give verbose debugging information. - * @return the value of the expression. - */ -bool ExpressionDefined(Lexer *lexer, StringSet *defines, bool verbose) -{ - bool value = ExpressionNot(lexer, defines, verbose); - - if (lexer->GetToken() != TOKEN_DEFINED) return value; - lexer->Lex(); - if (verbose) fprintf(stderr, "defined"); - bool open = (lexer->GetToken() == TOKEN_OPEN); - if (open) lexer->Lex(); - if (verbose) fprintf(stderr, open ? "(" : " "); - if (lexer->GetToken() == TOKEN_IDENTIFIER) { - if (verbose) fprintf(stderr, "%s", lexer->GetString()); - value = defines->find(lexer->GetString()) != defines->end(); - } - if (open) { - if (verbose) fprintf(stderr, ")"); - lexer->Lex(); - } - lexer->Lex(); - if (verbose) fprintf(stderr, "[%d]", value); - return value; -} - -/** - * Try to parse a 'expr && expr' expression. - * @param lexer the lexer to get tokens from. - * @param defines the set of known defines. - * @param verbose whether to give verbose debugging information. - * @return the value of the expression. - */ -bool ExpressionAnd(Lexer *lexer, StringSet *defines, bool verbose) -{ - bool value = ExpressionDefined(lexer, defines, verbose); - - for (;;) { - if (lexer->GetToken() != TOKEN_AND) return value; - if (verbose) fprintf(stderr, " && "); - lexer->Lex(); - value = value && ExpressionDefined(lexer, defines, verbose); - } -} - -/** - * Try to parse a 'expr || expr' expression. - * @param lexer the lexer to get tokens from. - * @param defines the set of known defines. - * @param verbose whether to give verbose debugging information. - * @return the value of the expression. - */ -bool ExpressionOr(Lexer *lexer, StringSet *defines, bool verbose) -{ - bool value = ExpressionAnd(lexer, defines, verbose); - - for (;;) { - if (lexer->GetToken() != TOKEN_OR) return value; - if (verbose) fprintf(stderr, " || "); - lexer->Lex(); - value = value || ExpressionAnd(lexer, defines, verbose); - } -} - -/** Enumerator to tell how long to ignore 'stuff'. */ -enum Ignore { - NOT_IGNORE, ///< No ignoring. - IGNORE_UNTIL_ELSE, ///< Ignore till a \c \#else is reached. - IGNORE_UNTIL_ENDIF, ///< Ignore till a \c \#endif is reached. -}; - -/** - * Scan a file for includes, defines and the lot. - * @param filename the name of the file to scan. - * @param ext the extension of the filename. - * @param header whether the file is a header or not. - * @param verbose whether to give verbose debugging information. - */ -void ScanFile(const char *filename, const char *ext, bool header, bool verbose) -{ - static StringSet defines; - static std::stack ignore; - /* Copy in the default defines (parameters of depend) */ - if (!header) { - for (StringSet::iterator it = _defines.begin(); it != _defines.end(); it++) { - defines.insert(strdup(*it)); - } - } - - File file(filename); - Lexer lexer(&file); - - /* Start the lexing! */ - lexer.Lex(); - - while (lexer.GetToken() != TOKEN_END) { - switch (lexer.GetToken()) { - /* We reached the end of the file... yay, we're done! */ - case TOKEN_END: break; - - /* The line started with a # (minus whitespace) */ - case TOKEN_SHARP: - lexer.Lex(); - switch (lexer.GetToken()) { - case TOKEN_INCLUDE: - if (verbose) fprintf(stderr, "%s #include ", filename); - lexer.Lex(); - switch (lexer.GetToken()) { - case TOKEN_LOCAL: - case TOKEN_GLOBAL: { - if (verbose) fprintf(stderr, "%s", lexer.GetString()); - if (!ignore.empty() && ignore.top() != NOT_IGNORE) { - if (verbose) fprintf(stderr, " (ignored)"); - break; - } - const char *h = GeneratePath(file.GetDirname(), lexer.GetString(), lexer.GetToken() == TOKEN_LOCAL); - if (h != nullptr) { - StringMap::iterator it = _headers.find(h); - if (it == _headers.end()) { - it = (_headers.insert(StringMapItem(strdup(h), new StringSet()))).first; - if (verbose) fprintf(stderr, "\n"); - ScanFile(h, ext, true, verbose); - } - StringMap::iterator curfile; - if (header) { - curfile = _headers.find(filename); - } else { - /* Replace the extension with the provided extension of '.o'. */ - char path[PATH_MAX]; - strecpy(path, filename, lastof(path)); - *(strrchr(path, '.')) = '\0'; - strecat(path, ext != nullptr ? ext : ".o", lastof(path)); - curfile = _files.find(path); - if (curfile == _files.end()) { - curfile = (_files.insert(StringMapItem(strdup(path), new StringSet()))).first; - } - } - if (it != _headers.end()) { - for (StringSet::iterator header = it->second->begin(); header != it->second->end(); header++) { - if (curfile->second->find(*header) == curfile->second->end()) curfile->second->insert(strdup(*header)); - } - } - if (curfile->second->find(h) == curfile->second->end()) curfile->second->insert(strdup(h)); - free(h); - } - } - /* FALL THROUGH */ - default: break; - } - break; - - case TOKEN_DEFINE: - if (verbose) fprintf(stderr, "%s #define ", filename); - lexer.Lex(); - if (lexer.GetToken() == TOKEN_IDENTIFIER) { - if (verbose) fprintf(stderr, "%s", lexer.GetString()); - if (!ignore.empty() && ignore.top() != NOT_IGNORE) { - if (verbose) fprintf(stderr, " (ignored)"); - break; - } - if (defines.find(lexer.GetString()) == defines.end()) defines.insert(strdup(lexer.GetString())); - lexer.Lex(); - } - break; - - case TOKEN_UNDEF: - if (verbose) fprintf(stderr, "%s #undef ", filename); - lexer.Lex(); - if (lexer.GetToken() == TOKEN_IDENTIFIER) { - if (verbose) fprintf(stderr, "%s", lexer.GetString()); - if (!ignore.empty() && ignore.top() != NOT_IGNORE) { - if (verbose) fprintf(stderr, " (ignored)"); - break; - } - StringSet::iterator it = defines.find(lexer.GetString()); - if (it != defines.end()) { - free(*it); - defines.erase(it); - } - lexer.Lex(); - } - break; - - case TOKEN_ENDIF: - if (verbose) fprintf(stderr, "%s #endif", filename); - lexer.Lex(); - if (!ignore.empty()) ignore.pop(); - if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); - break; - - case TOKEN_ELSE: { - if (verbose) fprintf(stderr, "%s #else", filename); - lexer.Lex(); - Ignore last = ignore.empty() ? NOT_IGNORE : ignore.top(); - if (!ignore.empty()) ignore.pop(); - if (ignore.empty() || ignore.top() == NOT_IGNORE) { - ignore.push(last == IGNORE_UNTIL_ELSE ? NOT_IGNORE : IGNORE_UNTIL_ENDIF); - } else { - ignore.push(IGNORE_UNTIL_ENDIF); - } - if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); - break; - } - - case TOKEN_ELIF: { - if (verbose) fprintf(stderr, "%s #elif ", filename); - lexer.Lex(); - Ignore last = ignore.empty() ? NOT_IGNORE : ignore.top(); - if (!ignore.empty()) ignore.pop(); - if (ignore.empty() || ignore.top() == NOT_IGNORE) { - bool value = ExpressionOr(&lexer, &defines, verbose); - ignore.push(last == IGNORE_UNTIL_ELSE ? (value ? NOT_IGNORE : IGNORE_UNTIL_ELSE) : IGNORE_UNTIL_ENDIF); - } else { - ignore.push(IGNORE_UNTIL_ENDIF); - } - if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); - break; - } - - case TOKEN_IF: { - if (verbose) fprintf(stderr, "%s #if ", filename); - lexer.Lex(); - if (ignore.empty() || ignore.top() == NOT_IGNORE) { - bool value = ExpressionOr(&lexer, &defines, verbose); - ignore.push(value ? NOT_IGNORE : IGNORE_UNTIL_ELSE); - } else { - ignore.push(IGNORE_UNTIL_ENDIF); - } - if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); - break; - } - - case TOKEN_IFDEF: - if (verbose) fprintf(stderr, "%s #ifdef ", filename); - lexer.Lex(); - if (lexer.GetToken() == TOKEN_IDENTIFIER) { - bool value = defines.find(lexer.GetString()) != defines.end(); - if (verbose) fprintf(stderr, "%s[%d]", lexer.GetString(), value); - if (ignore.empty() || ignore.top() == NOT_IGNORE) { - ignore.push(value ? NOT_IGNORE : IGNORE_UNTIL_ELSE); - } else { - ignore.push(IGNORE_UNTIL_ENDIF); - } - } - if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); - break; - - case TOKEN_IFNDEF: - if (verbose) fprintf(stderr, "%s #ifndef ", filename); - lexer.Lex(); - if (lexer.GetToken() == TOKEN_IDENTIFIER) { - bool value = defines.find(lexer.GetString()) != defines.end(); - if (verbose) fprintf(stderr, "%s[%d]", lexer.GetString(), value); - if (ignore.empty() || ignore.top() == NOT_IGNORE) { - ignore.push(!value ? NOT_IGNORE : IGNORE_UNTIL_ELSE); - } else { - ignore.push(IGNORE_UNTIL_ENDIF); - } - } - if (verbose) fprintf(stderr, " -> %signore", (!ignore.empty() && ignore.top() != NOT_IGNORE) ? "" : "not "); - break; - - default: - if (verbose) fprintf(stderr, "%s #", filename); - lexer.Lex(); - break; - } - if (verbose) fprintf(stderr, "\n"); - /* FALL THROUGH */ - default: - /* Ignore the rest of the garbage on this line */ - while (lexer.GetToken() != TOKEN_EOL && lexer.GetToken() != TOKEN_END) lexer.Lex(); - lexer.Lex(); - break; - } - } - - if (!header) { - for (StringSet::iterator it = defines.begin(); it != defines.end(); it++) { - free(*it); - } - defines.clear(); - while (!ignore.empty()) ignore.pop(); - } -} - -/** - * Entry point. Arguably the most common function in all applications. - * @param argc the number of arguments. - * @param argv the actual arguments. - * @return return value for the caller to tell we succeed or not. - */ -int main(int argc, char *argv[]) -{ - bool ignorenext = true; - char *filename = nullptr; - char *ext = nullptr; - char *delimiter = nullptr; - bool append = false; - bool verbose = false; - - for (int i = 0; i < argc; i++) { - if (ignorenext) { - ignorenext = false; - continue; - } - if (argv[i][0] == '-') { - /* Append */ - if (strncmp(argv[i], "-a", 2) == 0) append = true; - /* Include dir */ - if (strncmp(argv[i], "-I", 2) == 0) { - if (argv[i][2] == '\0') { - i++; - _include_dirs.insert(strdup(argv[i])); - } else { - _include_dirs.insert(strdup(&argv[i][2])); - } - continue; - } - /* Define */ - if (strncmp(argv[i], "-D", 2) == 0) { - char *p = strchr(argv[i], '='); - if (p != nullptr) *p = '\0'; - _defines.insert(strdup(&argv[i][2])); - continue; - } - /* Output file */ - if (strncmp(argv[i], "-f", 2) == 0) { - if (filename != nullptr) continue; - filename = strdup(&argv[i][2]); - continue; - } - /* Object file extension */ - if (strncmp(argv[i], "-o", 2) == 0) { - if (ext != nullptr) continue; - ext = strdup(&argv[i][2]); - continue; - } - /* Starting string delimiter */ - if (strncmp(argv[i], "-s", 2) == 0) { - if (delimiter != nullptr) continue; - delimiter = strdup(&argv[i][2]); - continue; - } - /* Verbose */ - if (strncmp(argv[i], "-v", 2) == 0) verbose = true; - continue; - } - ScanFile(argv[i], ext, false, verbose); - } - - /* Default output file is Makefile */ - if (filename == nullptr) filename = strdup("Makefile"); - - /* Default delimiter string */ - if (delimiter == nullptr) delimiter = strdup("# DO NOT DELETE"); - - char backup[PATH_MAX]; - strecpy(backup, filename, lastof(backup)); - strecat(backup, ".bak", lastof(backup)); - - char *content = nullptr; - long size = 0; - - /* Read in the current file; so we can overwrite everything from the - * end of non-depend data marker down till the end. */ - FILE *src = fopen(filename, "rb"); - if (src != nullptr) { - fseek(src, 0, SEEK_END); - if ((size = ftell(src)) < 0) { - fprintf(stderr, "Could not read %s\n", filename); - exit(-2); - } - rewind(src); - content = (char*)malloc(size * sizeof(*content)); - if (fread(content, 1, size, src) != (size_t)size) { - fprintf(stderr, "Could not read %s\n", filename); - exit(-2); - } - fclose(src); - } - - FILE *dst = fopen(filename, "w"); - bool found_delimiter = false; - - if (size != 0) { - src = fopen(backup, "wb"); - if (fwrite(content, 1, size, src) != (size_t)size) { - fprintf(stderr, "Could not write %s\n", filename); - exit(-2); - } - fclose(src); - - /* Then append it to the real file. */ - src = fopen(backup, "r"); - while (fgets(content, size, src) != nullptr) { - fputs(content, dst); - if (!strncmp(content, delimiter, strlen(delimiter))) found_delimiter = true; - if (!append && found_delimiter) break; - } - fclose(src); - } - if (!found_delimiter) fprintf(dst, "\n%s\n", delimiter); - - for (StringMap::iterator it = _files.begin(); it != _files.end(); it++) { - for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) { - fprintf(dst, "%s: %s\n", it->first, *h); - } - } - - /* Clean up our mess. */ - fclose(dst); - - free(delimiter); - free(filename); - free(ext); - free(content); - - for (StringMap::iterator it = _files.begin(); it != _files.end(); it++) { - for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) { - free(*h); - } - it->second->clear(); - delete it->second; - free(it->first); - } - _files.clear(); - - for (StringMap::iterator it = _headers.begin(); it != _headers.end(); it++) { - for (StringSet::iterator h = it->second->begin(); h != it->second->end(); h++) { - free(*h); - } - it->second->clear(); - delete it->second; - free(it->first); - } - _headers.clear(); - - for (StringSet::iterator it = _defines.begin(); it != _defines.end(); it++) { - free(*it); - } - _defines.clear(); - - for (StringSet::iterator it = _include_dirs.begin(); it != _include_dirs.end(); it++) { - free(*it); - } - _include_dirs.clear(); - - return 0; -} diff --git a/src/game/CMakeLists.txt b/src/game/CMakeLists.txt new file mode 100644 index 0000000000..aafb5a7b8d --- /dev/null +++ b/src/game/CMakeLists.txt @@ -0,0 +1,14 @@ +add_files( + game.hpp + game_config.cpp + game_config.hpp + game_core.cpp + game_info.cpp + game_info.hpp + game_instance.cpp + game_instance.hpp + game_scanner.cpp + game_scanner.hpp + game_text.cpp + game_text.hpp +) diff --git a/src/lang/CMakeLists.txt b/src/lang/CMakeLists.txt new file mode 100644 index 0000000000..00b554126f --- /dev/null +++ b/src/lang/CMakeLists.txt @@ -0,0 +1,122 @@ +set(LANG_SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/afrikaans.txt + ${CMAKE_CURRENT_SOURCE_DIR}/arabic_egypt.txt + ${CMAKE_CURRENT_SOURCE_DIR}/basque.txt + ${CMAKE_CURRENT_SOURCE_DIR}/belarusian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/brazilian_portuguese.txt + ${CMAKE_CURRENT_SOURCE_DIR}/bulgarian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/catalan.txt + ${CMAKE_CURRENT_SOURCE_DIR}/croatian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/czech.txt + ${CMAKE_CURRENT_SOURCE_DIR}/danish.txt + ${CMAKE_CURRENT_SOURCE_DIR}/dutch.txt + ${CMAKE_CURRENT_SOURCE_DIR}/english.txt + ${CMAKE_CURRENT_SOURCE_DIR}/english_AU.txt + ${CMAKE_CURRENT_SOURCE_DIR}/english_US.txt + ${CMAKE_CURRENT_SOURCE_DIR}/esperanto.txt + ${CMAKE_CURRENT_SOURCE_DIR}/estonian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/faroese.txt + ${CMAKE_CURRENT_SOURCE_DIR}/finnish.txt + ${CMAKE_CURRENT_SOURCE_DIR}/french.txt + ${CMAKE_CURRENT_SOURCE_DIR}/gaelic.txt + ${CMAKE_CURRENT_SOURCE_DIR}/galician.txt + ${CMAKE_CURRENT_SOURCE_DIR}/german.txt + ${CMAKE_CURRENT_SOURCE_DIR}/greek.txt + ${CMAKE_CURRENT_SOURCE_DIR}/hebrew.txt + ${CMAKE_CURRENT_SOURCE_DIR}/hungarian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/icelandic.txt + ${CMAKE_CURRENT_SOURCE_DIR}/indonesian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/irish.txt + ${CMAKE_CURRENT_SOURCE_DIR}/italian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/japanese.txt + ${CMAKE_CURRENT_SOURCE_DIR}/korean.txt + ${CMAKE_CURRENT_SOURCE_DIR}/latin.txt + ${CMAKE_CURRENT_SOURCE_DIR}/latvian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/lithuanian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/luxembourgish.txt + ${CMAKE_CURRENT_SOURCE_DIR}/malay.txt + ${CMAKE_CURRENT_SOURCE_DIR}/norwegian_bokmal.txt + ${CMAKE_CURRENT_SOURCE_DIR}/norwegian_nynorsk.txt + ${CMAKE_CURRENT_SOURCE_DIR}/polish.txt + ${CMAKE_CURRENT_SOURCE_DIR}/portuguese.txt + ${CMAKE_CURRENT_SOURCE_DIR}/romanian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/russian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/serbian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/simplified_chinese.txt + ${CMAKE_CURRENT_SOURCE_DIR}/slovak.txt + ${CMAKE_CURRENT_SOURCE_DIR}/slovenian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/spanish.txt + ${CMAKE_CURRENT_SOURCE_DIR}/spanish_MX.txt + ${CMAKE_CURRENT_SOURCE_DIR}/swedish.txt + ${CMAKE_CURRENT_SOURCE_DIR}/tamil.txt + ${CMAKE_CURRENT_SOURCE_DIR}/thai.txt + ${CMAKE_CURRENT_SOURCE_DIR}/traditional_chinese.txt + ${CMAKE_CURRENT_SOURCE_DIR}/turkish.txt + ${CMAKE_CURRENT_SOURCE_DIR}/ukrainian.txt + ${CMAKE_CURRENT_SOURCE_DIR}/vietnamese.txt + ${CMAKE_CURRENT_SOURCE_DIR}/welsh.txt +) + +set(LANG_BINARY_DIR ${CMAKE_BINARY_DIR}/lang) + +# Walk over all the (finished) language files, and generate a command to compile them +foreach(LANG_SOURCE_FILE IN LISTS LANG_SOURCE_FILES) + get_filename_component(LANG_SOURCE_FILE_NAME_WE ${LANG_SOURCE_FILE} NAME_WE) + + set(LANG_BINARY_FILE ${LANG_BINARY_DIR}/${LANG_SOURCE_FILE_NAME_WE}.lng) + + add_custom_command(OUTPUT ${LANG_BINARY_FILE} + COMMAND ${CMAKE_COMMAND} -E make_directory ${LANG_BINARY_DIR} + COMMAND strgen + -s ${CMAKE_CURRENT_SOURCE_DIR} + -d ${LANG_BINARY_DIR} + ${LANG_SOURCE_FILE} + DEPENDS strgen + MAIN_DEPENDENCY ${LANG_SOURCE_FILE} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Compiling language ${LANG_SOURCE_FILE_NAME_WE}" + ) + + list(APPEND LANG_BINARY_FILES ${LANG_BINARY_FILE}) +endforeach(LANG_SOURCE_FILE) + +# Create a new target which compiles all language files +add_custom_target(language_files + DEPENDS + ${LANG_BINARY_FILES} +) +set_target_properties(language_files + PROPERTIES LANG_SOURCE_FILES "${LANG_SOURCE_FILES}" +) + + +set(GENERATED_BINARY_DIR ${CMAKE_BINARY_DIR}/generated) +set(TABLE_BINARY_DIR ${GENERATED_BINARY_DIR}/table) + +# Generate a command and target to create the strings table +add_custom_command_timestamp(OUTPUT ${TABLE_BINARY_DIR}/strings.h + COMMAND ${CMAKE_COMMAND} -E make_directory ${TABLE_BINARY_DIR} + COMMAND strgen + -s ${CMAKE_CURRENT_SOURCE_DIR} + -d ${TABLE_BINARY_DIR} + DEPENDS strgen ${LANG_SOURCE_FILES} + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating table/strings.h" +) +add_custom_target_timestamp(table_strings + DEPENDS + ${TABLE_BINARY_DIR}/strings.h +) + +add_library(languages + INTERFACE +) +target_include_directories(languages + INTERFACE + ${GENERATED_BINARY_DIR} +) +add_dependencies(languages + language_files + table_strings +) +add_library(openttd::languages ALIAS languages) diff --git a/src/linkgraph/CMakeLists.txt b/src/linkgraph/CMakeLists.txt new file mode 100644 index 0000000000..c3d73a15e1 --- /dev/null +++ b/src/linkgraph/CMakeLists.txt @@ -0,0 +1,22 @@ +add_files( + demands.cpp + demands.h + flowmapper.cpp + flowmapper.h + init.h + linkgraph.cpp + linkgraph.h + linkgraph_base.h + linkgraph_gui.cpp + linkgraph_gui.h + linkgraph_type.h + linkgraphjob.cpp + linkgraphjob.h + linkgraphjob_base.h + linkgraphschedule.cpp + linkgraphschedule.h + mcf.cpp + mcf.h + refresh.cpp + refresh.h +) diff --git a/src/misc/CMakeLists.txt b/src/misc/CMakeLists.txt new file mode 100644 index 0000000000..3a5363e7b0 --- /dev/null +++ b/src/misc/CMakeLists.txt @@ -0,0 +1,14 @@ +add_files( + array.hpp + binaryheap.hpp + blob.hpp + countedobj.cpp + countedptr.hpp + dbg_helpers.cpp + dbg_helpers.h + fixedsizearray.hpp + getoptdata.cpp + getoptdata.h + hashtable.hpp + str.hpp +) diff --git a/src/music/CMakeLists.txt b/src/music/CMakeLists.txt new file mode 100644 index 0000000000..0ae15fde26 --- /dev/null +++ b/src/music/CMakeLists.txt @@ -0,0 +1,54 @@ +if (NOT OPTION_DEDICATED) + add_files( + allegro_m.cpp + allegro_m.h + CONDITION Allegro_FOUND + ) + + add_files( + fluidsynth.cpp + fluidsynth.h + CONDITION Fluidsynth_FOUND + ) + + add_files( + cocoa_m.cpp + cocoa_m.h + CONDITION APPLE + ) + + add_files( + dmusic.cpp + dmusic.h + win32_m.cpp + win32_m.h + CONDITION WIN32 + ) + + add_files( + extmidi.cpp + extmidi.h + CONDITION UNIX + ) + + add_files( + bemidi.cpp + bemidi.h + CONDITION OPTION_HAIKU + ) + + add_files( + os2_m.cpp + os2_m.h + CONDITION OPTION_OS2 + ) +endif (NOT OPTION_DEDICATED) + +add_files( + midi.h + midifile.cpp + midifile.hpp + music_driver.hpp + null_m.cpp + null_m.h +) diff --git a/src/network/CMakeLists.txt b/src/network/CMakeLists.txt new file mode 100644 index 0000000000..1c27d62066 --- /dev/null +++ b/src/network/CMakeLists.txt @@ -0,0 +1,28 @@ +add_subdirectory(core) + +add_files( + network.cpp + network.h + network_admin.cpp + network_admin.h + network_base.h + network_chat_gui.cpp + network_client.cpp + network_client.h + network_command.cpp + network_content.cpp + network_content.h + network_content_gui.cpp + network_content_gui.h + network_func.h + network_gamelist.cpp + network_gamelist.h + network_gui.cpp + network_gui.h + network_internal.h + network_server.cpp + network_server.h + network_type.h + network_udp.cpp + network_udp.h +) diff --git a/src/network/core/CMakeLists.txt b/src/network/core/CMakeLists.txt new file mode 100644 index 0000000000..777d15d841 --- /dev/null +++ b/src/network/core/CMakeLists.txt @@ -0,0 +1,27 @@ +add_files( + address.cpp + address.h + config.h + core.cpp + core.h + game.h + host.cpp + host.h + os_abstraction.h + packet.cpp + packet.h + tcp.cpp + tcp.h + tcp_admin.cpp + tcp_admin.h + tcp_connect.cpp + tcp_content.cpp + tcp_content.h + tcp_game.cpp + tcp_game.h + tcp_http.cpp + tcp_http.h + tcp_listen.h + udp.cpp + udp.h +) diff --git a/src/os/CMakeLists.txt b/src/os/CMakeLists.txt new file mode 100644 index 0000000000..e302c448b5 --- /dev/null +++ b/src/os/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory(macosx) +add_subdirectory(os2) +add_subdirectory(unix) +add_subdirectory(windows) diff --git a/src/os/macosx/CMakeLists.txt b/src/os/macosx/CMakeLists.txt new file mode 100644 index 0000000000..e6b6c237b0 --- /dev/null +++ b/src/os/macosx/CMakeLists.txt @@ -0,0 +1,11 @@ +add_files( + crashlog_osx.cpp + macos.h + macos.mm + osx_stdafx.h + splash.cpp + splash.h + string_osx.cpp + string_osx.h + CONDITION APPLE +) diff --git a/src/os/os2/CMakeLists.txt b/src/os/os2/CMakeLists.txt new file mode 100644 index 0000000000..52534dbcbb --- /dev/null +++ b/src/os/os2/CMakeLists.txt @@ -0,0 +1,4 @@ +add_files( + os2.cpp + CONDITION OPTION_OS2 +) diff --git a/src/os/unix/CMakeLists.txt b/src/os/unix/CMakeLists.txt new file mode 100644 index 0000000000..b548d3bb21 --- /dev/null +++ b/src/os/unix/CMakeLists.txt @@ -0,0 +1,9 @@ +add_files( + crashlog_unix.cpp + CONDITION UNIX AND NOT APPLE AND NOT OPTION_OS2 +) + +add_files( + unix.cpp + CONDITION UNIX AND NOT OPTION_OS2 +) diff --git a/src/os/windows/CMakeLists.txt b/src/os/windows/CMakeLists.txt new file mode 100644 index 0000000000..19d1bd46e3 --- /dev/null +++ b/src/os/windows/CMakeLists.txt @@ -0,0 +1,8 @@ +add_files( + crashlog_win.cpp + string_uniscribe.cpp + string_uniscribe.h + win32.cpp + win32.h + CONDITION WIN32 +) diff --git a/src/os/windows/ottdres.rc.in b/src/os/windows/ottdres.rc.in index a2f8c28f57..741fa0e105 100644 --- a/src/os/windows/ottdres.rc.in +++ b/src/os/windows/ottdres.rc.in @@ -37,7 +37,7 @@ LANGUAGE LANG_NEUTRAL, SUBLANG_DEFAULT // Icon with lowest ID value placed first to ensure application icon // remains consistent on all systems. -100 ICON DISCARDABLE "../../../media/openttd.ico" +100 ICON DISCARDABLE "${CMAKE_SOURCE_DIR}/os/windows/openttd.ico" ///////////////////////////////////////////////////////////////////////////// // @@ -77,8 +77,8 @@ END // VS_VERSION_INFO VERSIONINFO - FILEVERSION 1,11,0,!!ISODATE!! - PRODUCTVERSION 1,11,0,!!ISODATE!! + FILEVERSION 1,11,0,${REV_ISODATE} + PRODUCTVERSION 1,11,0,${REV_ISODATE} FILEFLAGSMASK 0x3fL #ifdef _DEBUG FILEFLAGS 0x1L @@ -96,14 +96,14 @@ BEGIN VALUE "Comments", "This program is licensed under the GNU General Public License version 2.\0" VALUE "CompanyName", "OpenTTD Development Team\0" VALUE "FileDescription", "OpenTTD\0" - VALUE "FileVersion", "!!VERSION!!\0" + VALUE "FileVersion", "${REV_VERSION}\0" VALUE "InternalName", "openttd\0" - VALUE "LegalCopyright", "Copyright \xA9 OpenTTD Developers 2002-!!YEAR!!. All Rights Reserved.\0" + VALUE "LegalCopyright", "Copyright \xA9 OpenTTD Developers 2002-${REV_YEAR}. All Rights Reserved.\0" VALUE "LegalTrademarks", "\0" VALUE "OriginalFilename", "openttd.exe\0" VALUE "PrivateBuild", "\0" VALUE "ProductName", "OpenTTD\0" - VALUE "ProductVersion", "!!VERSION!!\0" + VALUE "ProductVersion", "${REV_VERSION}\0" VALUE "SpecialBuild", "-\0" END END @@ -116,7 +116,7 @@ END #endif // !_MAC #ifdef __MINGW32__ -1 24 "..\\..\\..\\projects\\dpi_aware.manifest" +1 24 "${CMAKE_SOURCE_DIR}/os/windows/openttd.manifest" #endif #endif // Neutral (Default) resources diff --git a/src/pathfinder/CMakeLists.txt b/src/pathfinder/CMakeLists.txt new file mode 100644 index 0000000000..2e275706f2 --- /dev/null +++ b/src/pathfinder/CMakeLists.txt @@ -0,0 +1,9 @@ +add_subdirectory(npf) +add_subdirectory(yapf) + +add_files( + follow_track.hpp + pathfinder_func.h + pathfinder_type.h + pf_performance_timer.hpp +) diff --git a/src/pathfinder/npf/CMakeLists.txt b/src/pathfinder/npf/CMakeLists.txt new file mode 100644 index 0000000000..e3ace57e52 --- /dev/null +++ b/src/pathfinder/npf/CMakeLists.txt @@ -0,0 +1,8 @@ +add_files( + aystar.cpp + aystar.h + npf.cpp + npf_func.h + queue.cpp + queue.h +) diff --git a/src/pathfinder/yapf/CMakeLists.txt b/src/pathfinder/yapf/CMakeLists.txt new file mode 100644 index 0000000000..170c1ad61d --- /dev/null +++ b/src/pathfinder/yapf/CMakeLists.txt @@ -0,0 +1,20 @@ +add_files( + nodelist.hpp + yapf.h + yapf.hpp + yapf_base.hpp + yapf_cache.h + yapf_common.hpp + yapf_costbase.hpp + yapf_costcache.hpp + yapf_costrail.hpp + yapf_destrail.hpp + yapf_node.hpp + yapf_node_rail.hpp + yapf_node_road.hpp + yapf_node_ship.hpp + yapf_rail.cpp + yapf_road.cpp + yapf_ship.cpp + yapf_type.hpp +) diff --git a/src/rev.cpp.in b/src/rev.cpp.in index 3f5b126dc1..16c403a67a 100644 --- a/src/rev.cpp.in +++ b/src/rev.cpp.in @@ -35,7 +35,7 @@ bool IsReleasedVersion() * * shows a "M", if the binary is made from modified source code. */ -const char _openttd_revision[] = "!!VERSION!!"; +const char _openttd_revision[] = "${REV_VERSION}"; /** * The text version of OpenTTD's build date. @@ -48,12 +48,12 @@ const char _openttd_build_date[] = __DATE__ " " __TIME__; /** * The git revision hash of this version. */ -const char _openttd_revision_hash[] = "!!GITHASH!!"; +const char _openttd_revision_hash[] = "${REV_HASH}"; /** * The year of this version. */ -const char _openttd_revision_year[] = "!!YEAR!!"; +const char _openttd_revision_year[] = "${REV_YEAR}"; /** * Let us know if current build was modified. This detection @@ -63,14 +63,14 @@ const char _openttd_revision_year[] = "!!YEAR!!"; * (compiling from sources without any version control software) * and 2 is for modified revision. */ -const byte _openttd_revision_modified = !!MODIFIED!!; +const byte _openttd_revision_modified = ${REV_MODIFIED}; /** * Indicate whether this is a tagged version. * If this is non-0, then _openttd_revision is the name of the tag, * and the version is likely a beta, release candidate, or real release. */ -const byte _openttd_revision_tagged = !!ISTAG!!; +const byte _openttd_revision_tagged = ${REV_ISTAG}; /** * The NewGRF revision of OTTD: @@ -85,4 +85,4 @@ const byte _openttd_revision_tagged = !!ISTAG!!; * final release will always have a lower version number than the released * version, thus making comparisons on specific revisions easy. */ -const uint32 _openttd_newgrf_version = 1 << 28 | 11 << 24 | 0 << 20 | !!ISSTABLETAG!! << 19 | 28004; +const uint32 _openttd_newgrf_version = 1 << 28 | 11 << 24 | 0 << 20 | ${REV_ISSTABLETAG} << 19 | 28004; diff --git a/src/saveload/CMakeLists.txt b/src/saveload/CMakeLists.txt new file mode 100644 index 0000000000..52f103fa7e --- /dev/null +++ b/src/saveload/CMakeLists.txt @@ -0,0 +1,43 @@ +add_files( + afterload.cpp + ai_sl.cpp + airport_sl.cpp + animated_tile_sl.cpp + autoreplace_sl.cpp + cargomonitor_sl.cpp + cargopacket_sl.cpp + cheat_sl.cpp + company_sl.cpp + depot_sl.cpp + economy_sl.cpp + engine_sl.cpp + game_sl.cpp + gamelog_sl.cpp + goal_sl.cpp + group_sl.cpp + industry_sl.cpp + labelmaps_sl.cpp + linkgraph_sl.cpp + map_sl.cpp + misc_sl.cpp + newgrf_sl.cpp + newgrf_sl.h + object_sl.cpp + oldloader.cpp + oldloader.h + oldloader_sl.cpp + order_sl.cpp + saveload.cpp + saveload.h + saveload_filter.h + saveload_internal.h + signs_sl.cpp + station_sl.cpp + storage_sl.cpp + strings_sl.cpp + story_sl.cpp + subsidy_sl.cpp + town_sl.cpp + vehicle_sl.cpp + waypoint_sl.cpp +) diff --git a/src/script/CMakeLists.txt b/src/script/CMakeLists.txt new file mode 100644 index 0000000000..e5915332c4 --- /dev/null +++ b/src/script/CMakeLists.txt @@ -0,0 +1,23 @@ +add_subdirectory(api) + +add_files( + script_config.cpp + script_config.hpp + script_fatalerror.hpp + script_info.cpp + script_info.hpp + script_info_dummy.cpp + script_instance.cpp + script_instance.hpp + script_scanner.cpp + script_scanner.hpp + script_storage.hpp + script_suspend.hpp + squirrel.cpp + squirrel.hpp + squirrel_class.hpp + squirrel_helper.hpp + squirrel_helper_type.hpp + squirrel_std.cpp + squirrel_std.hpp +) diff --git a/src/script/api/CMakeLists.txt b/src/script/api/CMakeLists.txt new file mode 100644 index 0000000000..9c665293c1 --- /dev/null +++ b/src/script/api/CMakeLists.txt @@ -0,0 +1,140 @@ +add_files( + ai_changelog.hpp + game_changelog.hpp + script_accounting.hpp + script_admin.hpp + script_airport.hpp + script_base.hpp + script_basestation.hpp + script_bridge.hpp + script_bridgelist.hpp + script_cargo.hpp + script_cargolist.hpp + script_cargomonitor.hpp + script_client.hpp + script_clientlist.hpp + script_company.hpp + script_companymode.hpp + script_controller.hpp + script_date.hpp + script_depotlist.hpp + script_engine.hpp + script_enginelist.hpp + script_error.hpp + script_event.hpp + script_event_types.hpp + script_execmode.hpp + script_game.hpp + script_gamesettings.hpp + script_goal.hpp + script_group.hpp + script_grouplist.hpp + script_industry.hpp + script_industrylist.hpp + script_industrytype.hpp + script_industrytypelist.hpp + script_info_docs.hpp + script_infrastructure.hpp + script_list.hpp + script_log.hpp + script_map.hpp + script_marine.hpp + script_news.hpp + script_object.hpp + script_order.hpp + script_priorityqueue.hpp + script_rail.hpp + script_railtypelist.hpp + script_road.hpp + script_roadtypelist.hpp + script_sign.hpp + script_signlist.hpp + script_station.hpp + script_stationlist.hpp + script_story_page.hpp + script_storypagelist.hpp + script_storypageelementlist.hpp + script_subsidy.hpp + script_subsidylist.hpp + script_testmode.hpp + script_text.hpp + script_tile.hpp + script_tilelist.hpp + script_town.hpp + script_townlist.hpp + script_tunnel.hpp + script_types.hpp + script_vehicle.hpp + script_vehiclelist.hpp + script_viewport.hpp + script_waypoint.hpp + script_waypointlist.hpp + script_window.hpp + script_accounting.cpp + script_admin.cpp + script_airport.cpp + script_base.cpp + script_basestation.cpp + script_bridge.cpp + script_bridgelist.cpp + script_cargo.cpp + script_cargolist.cpp + script_cargomonitor.cpp + script_client.cpp + script_clientlist.cpp + script_company.cpp + script_companymode.cpp + script_controller.cpp + script_date.cpp + script_depotlist.cpp + script_engine.cpp + script_enginelist.cpp + script_error.cpp + script_event.cpp + script_event_types.cpp + script_execmode.cpp + script_game.cpp + script_gamesettings.cpp + script_goal.cpp + script_group.cpp + script_grouplist.cpp + script_industry.cpp + script_industrylist.cpp + script_industrytype.cpp + script_industrytypelist.cpp + script_infrastructure.cpp + script_list.cpp + script_log.cpp + script_map.cpp + script_marine.cpp + script_news.cpp + script_object.cpp + script_order.cpp + script_priorityqueue.cpp + script_rail.cpp + script_railtypelist.cpp + script_road.cpp + script_roadtypelist.cpp + script_sign.cpp + script_signlist.cpp + script_station.cpp + script_stationlist.cpp + script_story_page.cpp + script_storypagelist.cpp + script_storypageelementlist.cpp + script_subsidy.cpp + script_subsidylist.cpp + script_testmode.cpp + script_text.cpp + script_tile.cpp + script_tilelist.cpp + script_town.cpp + script_townlist.cpp + script_tunnel.cpp + script_vehicle.cpp + script_vehiclelist.cpp + script_viewport.cpp + script_waypoint.cpp + script_waypointlist.cpp + script_window.cpp +) diff --git a/src/settingsgen/CMakeLists.txt b/src/settingsgen/CMakeLists.txt new file mode 100644 index 0000000000..e17b8ad6bf --- /dev/null +++ b/src/settingsgen/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 3.5) + +project(settingsgen) + +set(sourcefiles + settingsgen.cpp + ../core/alloc_func.cpp + ../misc/getoptdata.cpp + ../ini_load.cpp + ../string.cpp +) +add_definitions(-DSETTINGSGEN) +add_executable(settingsgen ${sourcefiles}) diff --git a/src/sound/CMakeLists.txt b/src/sound/CMakeLists.txt new file mode 100644 index 0000000000..35f65d1205 --- /dev/null +++ b/src/sound/CMakeLists.txt @@ -0,0 +1,37 @@ +if (NOT OPTION_DEDICATED) + add_files( + allegro_s.cpp + allegro_s.h + CONDITION Allegro_FOUND + ) + + add_files( + sdl_s.cpp + sdl_s.h + CONDITION SDL_FOUND + ) + + add_files( + cocoa_s.cpp + cocoa_s.h + CONDITION APPLE + ) + + add_files( + win32_s.cpp + win32_s.h + CONDITION WIN32 + ) + + add_files( + xaudio2_s.cpp + xaudio2_s.h + CONDITION WIN32 AND XAUDIO2_FOUND + ) +endif (NOT OPTION_DEDICATED) + +add_files( + sound_driver.hpp + null_s.cpp + null_s.h +) diff --git a/src/spriteloader/CMakeLists.txt b/src/spriteloader/CMakeLists.txt new file mode 100644 index 0000000000..5d6a2f865e --- /dev/null +++ b/src/spriteloader/CMakeLists.txt @@ -0,0 +1,5 @@ +add_files( + grf.cpp + grf.hpp + spriteloader.hpp +) diff --git a/src/stdafx.h b/src/stdafx.h index 4fb84a956e..c520925537 100644 --- a/src/stdafx.h +++ b/src/stdafx.h @@ -424,17 +424,14 @@ void NORETURN CDECL usererror(const char *str, ...) WARN_FORMAT(1, 2); void NORETURN CDECL error(const char *str, ...) WARN_FORMAT(1, 2); #define NOT_REACHED() error("NOT_REACHED triggered at line %i of %s", __LINE__, __FILE__) -/* For non-debug builds with assertions enabled use the special assertion handler: - * - For MSVC: NDEBUG is set for all release builds and WITH_ASSERT overrides the disabling of asserts. - * - For non MSVC: NDEBUG is set when assertions are disables, _DEBUG is set for non-release builds. - */ -#if (defined(_MSC_VER) && defined(NDEBUG) && defined(WITH_ASSERT)) || (!defined(_MSC_VER) && !defined(NDEBUG) && !defined(_DEBUG)) +/* For non-debug builds with assertions enabled use the special assertion handler. */ +#if defined(NDEBUG) && defined(WITH_ASSERT) #undef assert #define assert(expression) if (!(expression)) error("Assertion failed at line %i of %s: %s", __LINE__, __FILE__, #expression); #endif -/* Asserts are enabled if NDEBUG isn't defined, or if we are using MSVC and WITH_ASSERT is defined. */ -#if !defined(NDEBUG) || (defined(_MSC_VER) && defined(WITH_ASSERT)) +/* Asserts are enabled if NDEBUG isn't defined or WITH_ASSERT is defined. */ +#if !defined(NDEBUG) || defined(WITH_ASSERT) #define OTTD_ASSERT #endif diff --git a/src/strgen/CMakeLists.txt b/src/strgen/CMakeLists.txt new file mode 100644 index 0000000000..b8f61cde3b --- /dev/null +++ b/src/strgen/CMakeLists.txt @@ -0,0 +1,25 @@ +cmake_minimum_required(VERSION 3.5) + +project(strgen) + +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/../../cmake") + +set(sourcefiles + strgen.cpp + strgen_base.cpp + ../core/alloc_func.cpp + ../misc/getoptdata.cpp + ../string.cpp +) +add_definitions(-DSTRGEN) +add_executable(strgen ${sourcefiles}) + +include(Endian) +add_endian_definition() + + +# Source Files +add_files(strgen_base.cpp) + +# Header Files +add_files(strgen.h) diff --git a/src/table/CMakeLists.txt b/src/table/CMakeLists.txt new file mode 100644 index 0000000000..23b4724e33 --- /dev/null +++ b/src/table/CMakeLists.txt @@ -0,0 +1,83 @@ +set(GENERATED_BINARY_DIR ${CMAKE_BINARY_DIR}/generated) +set(TABLE_BINARY_DIR ${GENERATED_BINARY_DIR}/table) + +set(TABLE_INI_SOURCE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/company_settings.ini + ${CMAKE_CURRENT_SOURCE_DIR}/currency_settings.ini + ${CMAKE_CURRENT_SOURCE_DIR}/gameopt_settings.ini + ${CMAKE_CURRENT_SOURCE_DIR}/misc_settings.ini + ${CMAKE_CURRENT_SOURCE_DIR}/settings.ini + ${CMAKE_CURRENT_SOURCE_DIR}/win32_settings.ini + ${CMAKE_CURRENT_SOURCE_DIR}/window_settings.ini +) + +# Generate a command and target to create the settings table +add_custom_command_timestamp(OUTPUT ${TABLE_BINARY_DIR}/settings.h + COMMAND ${CMAKE_COMMAND} -E make_directory ${TABLE_BINARY_DIR} + COMMAND settingsgen + -o ${TABLE_BINARY_DIR}/settings.h + -b ${CMAKE_SOURCE_DIR}/src/table/settings.h.preamble + -a ${CMAKE_SOURCE_DIR}/src/table/settings.h.postamble + ${TABLE_INI_SOURCE_FILES} + DEPENDS settingsgen ${TABLE_INI_SOURCE_FILES} + ${CMAKE_SOURCE_DIR}/src/table/settings.h.preamble + ${CMAKE_SOURCE_DIR}/src/table/settings.h.postamble + WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} + COMMENT "Generating table/settings.h" +) +add_custom_target_timestamp(table_settings + DEPENDS + ${TABLE_BINARY_DIR}/settings.h +) + +add_library(settings + INTERFACE +) +target_include_directories(settings + INTERFACE + ${GENERATED_BINARY_DIR} +) +add_dependencies(settings + table_settings +) +add_library(openttd::settings ALIAS settings) + +add_files( + airport_defaults.h + airport_movement.h + airporttile_ids.h + airporttiles.h + animcursors.h + autorail.h + bridge_land.h + build_industry.h + cargo_const.h + clear_land.h + control_codes.h + elrail_data.h + engines.h + genland.h + heightmap_colours.h + industry_land.h + landscape_sprite.h + newgrf_debug_data.h + object_land.h + palette_convert.h + palettes.h + pricebase.h + railtypes.h + road_land.h + roadtypes.h + roadveh_movement.h + sprites.h + station_land.h + strgen_tables.h + string_colours.h + town_land.h + townname.h + track_land.h + train_cmd.h + tree_land.h + unicode.h + water_land.h +) diff --git a/src/video/CMakeLists.txt b/src/video/CMakeLists.txt new file mode 100644 index 0000000000..c6251e9391 --- /dev/null +++ b/src/video/CMakeLists.txt @@ -0,0 +1,35 @@ +add_subdirectory(cocoa) + +if (NOT OPTION_DEDICATED) + add_files( + allegro_v.cpp + allegro_v.h + CONDITION Allegro_FOUND + ) + + add_files( + sdl_v.cpp + sdl_v.h + CONDITION SDL_FOUND + ) + + add_files( + sdl2_v.cpp + sdl2_v.h + CONDITION SDL2_FOUND + ) + + add_files( + win32_v.cpp + win32_v.h + CONDITION WIN32 + ) +endif (NOT OPTION_DEDICATED) + +add_files( + dedicated_v.cpp + dedicated_v.h + null_v.cpp + null_v.h + video_driver.hpp +) diff --git a/src/video/cocoa/CMakeLists.txt b/src/video/cocoa/CMakeLists.txt new file mode 100644 index 0000000000..4fff132f37 --- /dev/null +++ b/src/video/cocoa/CMakeLists.txt @@ -0,0 +1,8 @@ +add_files( + cocoa_keys.h + cocoa_v.h + cocoa_v.mm + event.mm + wnd_quartz.mm + CONDITION APPLE +) diff --git a/src/widgets/CMakeLists.txt b/src/widgets/CMakeLists.txt new file mode 100644 index 0000000000..18ecd529e8 --- /dev/null +++ b/src/widgets/CMakeLists.txt @@ -0,0 +1,61 @@ +add_files( + ai_widget.h + airport_widget.h + autoreplace_widget.h + bootstrap_widget.h + bridge_widget.h + build_vehicle_widget.h + cheat_widget.h + company_widget.h + console_widget.h + date_widget.h + depot_widget.h + dock_widget.h + dropdown.cpp + dropdown_func.h + dropdown_type.h + dropdown_widget.h + engine_widget.h + error_widget.h + fios_widget.h + framerate_widget.h + genworld_widget.h + goal_widget.h + graph_widget.h + group_widget.h + highscore_widget.h + industry_widget.h + intro_widget.h + link_graph_legend_widget.h + main_widget.h + misc_widget.h + music_widget.h + network_chat_widget.h + network_content_widget.h + network_widget.h + newgrf_debug_widget.h + newgrf_widget.h + news_widget.h + object_widget.h + order_widget.h + osk_widget.h + rail_widget.h + road_widget.h + screenshot_widget.h + settings_widget.h + sign_widget.h + smallmap_widget.h + station_widget.h + statusbar_widget.h + story_widget.h + subsidy_widget.h + terraform_widget.h + timetable_widget.h + toolbar_widget.h + town_widget.h + transparency_widget.h + tree_widget.h + vehicle_widget.h + viewport_widget.h + waypoint_widget.h +)