cmake_minimum_required(VERSION 3.16...3.28 FATAL_ERROR) project(liblcf VERSION 0.8.1 LANGUAGES CXX) list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/builds/cmake/Modules) include(ConfigureWindows) include(MiscUtils) # Compilation options option(BUILD_SHARED_LIBS "Build shared library, disable for building the static library (default: ON)" ON) option(LIBLCF_WITH_INI "INI parsing support (inih, required when building EasyRPG Player, default: ON)" ON) option(LIBLCF_WITH_ICU "ICU encoding handling (when disabled only windows-1252 is supported, default: ON)" ON) option(LIBLCF_WITH_XML "XML reading support (expat, default: ON)" ON) option(LIBLCF_UPDATE_MIMEDB "Whether to run update-mime-database after install (default: ON)" ON) option(LIBLCF_ENABLE_TOOLS "Whether to build the tools (default: ON)" ${LIBLCF_MAIN_PROJECT}) option(LIBLCF_ENABLE_TESTS "Whether to build the unit tests (default: ON)" ${LIBLCF_MAIN_PROJECT}) option(LIBLCF_ENABLE_BENCHMARKS "Whether to build the benchmarks (default: OFF)" OFF) option(LIBLCF_ENABLE_INSTALL "Whether to add an install target (default: ON)" ${LIBLCF_MAIN_PROJECT}) set(CMAKE_DEBUG_POSTFIX "d" CACHE STRING "Override CMAKE_DEBUG_POSTFIX.") # Dependencies provided by CMake Presets list(APPEND CMAKE_PREFIX_PATH "${LIBLCF_PREFIX_PATH_APPEND}") # C++17 is required set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS ON) # lcf library files set(LCF_SOURCES src/dbarray.cpp src/dbstring_struct.cpp src/encoder.cpp src/ldb_equipment.cpp src/ldb_eventcommand.cpp src/ldb_parameters.cpp src/ldb_reader.cpp src/lmt_reader.cpp src/lmt_rect.cpp src/lmt_treemap.cpp src/lmu_movecommand.cpp src/lmu_reader.cpp src/log.h src/log_handler.cpp src/lsd_reader.cpp src/reader_flags.cpp src/reader_lcf.cpp src/reader_struct.h src/reader_struct_impl.h src/reader_util.cpp src/reader_xml.cpp src/rpg_setup.cpp src/rpg_terms.cpp src/saveopt.cpp src/writer_lcf.cpp src/writer_xml.cpp src/generated/fwd_flags_impl.h src/generated/fwd_flags_instance.h src/generated/fwd_struct_impl.h src/generated/ldb_actor.cpp src/generated/ldb_animation.cpp src/generated/ldb_animationcelldata.cpp src/generated/ldb_animationframe.cpp src/generated/ldb_animationtiming.cpp src/generated/ldb_attribute.cpp src/generated/ldb_battlecommand.cpp src/generated/ldb_battlecommands.cpp src/generated/ldb_battleranimation.cpp src/generated/ldb_battleranimationitemskill.cpp src/generated/ldb_battleranimationpose.cpp src/generated/ldb_battleranimationweapon.cpp src/generated/ldb_chipset.cpp src/generated/ldb_class.cpp src/generated/ldb_commonevent.cpp src/generated/ldb_database.cpp src/generated/ldb_enemy.cpp src/generated/ldb_enemyaction.cpp src/generated/ldb_item.cpp src/generated/ldb_learning.cpp src/generated/ldb_music.cpp src/generated/ldb_skill.cpp src/generated/ldb_sound.cpp src/generated/ldb_state.cpp src/generated/ldb_stringvariable.cpp src/generated/ldb_switch.cpp src/generated/ldb_system.cpp src/generated/ldb_terms.cpp src/generated/ldb_terrain.cpp src/generated/ldb_terrain_special_flags.h src/generated/ldb_testbattler.cpp src/generated/ldb_troop.cpp src/generated/ldb_troopmember.cpp src/generated/ldb_trooppage.cpp src/generated/ldb_trooppagecondition.cpp src/generated/ldb_trooppagecondition_flags.h src/generated/ldb_variable.cpp src/generated/lmt_encounter.cpp src/generated/lmt_mapinfo.cpp src/generated/lmt_start.cpp src/generated/lmu_event.cpp src/generated/lmu_eventpage.cpp src/generated/lmu_eventpagecondition.cpp src/generated/lmu_eventpagecondition_flags.h src/generated/lmu_map.cpp src/generated/lmu_moveroute.cpp src/generated/lsd_save.cpp src/generated/lsd_saveactor.cpp src/generated/lsd_savecommonevent.cpp src/generated/lsd_saveeasyrpgdata.cpp src/generated/lsd_saveeasyrpgtext.cpp src/generated/lsd_saveeasyrpgtext_flags.h src/generated/lsd_saveeasyrpgwindow.cpp src/generated/lsd_saveeasyrpgwindow_flags.h src/generated/lsd_saveeventexecframe.cpp src/generated/lsd_saveeventexecframe_easyrpg_runtime_flags.h src/generated/lsd_saveeventexecstate.cpp src/generated/lsd_saveeventexecstate_easyrpg_runtime_flags.h src/generated/lsd_saveinventory.cpp src/generated/lsd_savemapevent.cpp src/generated/lsd_savemapeventbase.cpp src/generated/lsd_savemapeventbase_easyrpg_runtime_flags.h src/generated/lsd_savemapinfo.cpp src/generated/lsd_savepanorama.cpp src/generated/lsd_savepartylocation.cpp src/generated/lsd_savepicture.cpp src/generated/lsd_savepicture_flags.h src/generated/lsd_savescreen.cpp src/generated/lsd_savesystem.cpp src/generated/lsd_savesystem_maniac_message_hook_flags.h src/generated/lsd_savetarget.cpp src/generated/lsd_savetitle.cpp src/generated/lsd_savevehiclelocation.cpp src/generated/rpg_actor.cpp src/generated/rpg_animation.cpp src/generated/rpg_animationcelldata.cpp src/generated/rpg_animationframe.cpp src/generated/rpg_animationtiming.cpp src/generated/rpg_attribute.cpp src/generated/rpg_battlecommand.cpp src/generated/rpg_battlecommands.cpp src/generated/rpg_battleranimation.cpp src/generated/rpg_battleranimationitemskill.cpp src/generated/rpg_battleranimationpose.cpp src/generated/rpg_battleranimationweapon.cpp src/generated/rpg_chipset.cpp src/generated/rpg_class.cpp src/generated/rpg_commonevent.cpp src/generated/rpg_database.cpp src/generated/rpg_encounter.cpp src/generated/rpg_enemy.cpp src/generated/rpg_enemyaction.cpp src/generated/rpg_equipment.cpp src/generated/rpg_event.cpp src/generated/rpg_eventcommand.cpp src/generated/rpg_eventpage.cpp src/generated/rpg_eventpagecondition.cpp src/generated/rpg_item.cpp src/generated/rpg_learning.cpp src/generated/rpg_map.cpp src/generated/rpg_mapinfo.cpp src/generated/rpg_movecommand.cpp src/generated/rpg_moveroute.cpp src/generated/rpg_music.cpp src/generated/rpg_parameters.cpp src/generated/rpg_rect.cpp src/generated/rpg_save.cpp src/generated/rpg_saveactor.cpp src/generated/rpg_savecommonevent.cpp src/generated/rpg_saveeasyrpgdata.cpp src/generated/rpg_saveeasyrpgtext.cpp src/generated/rpg_saveeasyrpgwindow.cpp src/generated/rpg_saveeventexecframe.cpp src/generated/rpg_saveeventexecstate.cpp src/generated/rpg_saveinventory.cpp src/generated/rpg_savemapevent.cpp src/generated/rpg_savemapeventbase.cpp src/generated/rpg_savemapinfo.cpp src/generated/rpg_savepanorama.cpp src/generated/rpg_savepartylocation.cpp src/generated/rpg_savepicture.cpp src/generated/rpg_savescreen.cpp src/generated/rpg_savesystem.cpp src/generated/rpg_savetarget.cpp src/generated/rpg_savetitle.cpp src/generated/rpg_savevehiclelocation.cpp src/generated/rpg_skill.cpp src/generated/rpg_sound.cpp src/generated/rpg_start.cpp src/generated/rpg_state.cpp src/generated/rpg_stringvariable.cpp src/generated/rpg_switch.cpp src/generated/rpg_system.cpp src/generated/rpg_terms.cpp src/generated/rpg_terrain.cpp src/generated/rpg_testbattler.cpp src/generated/rpg_treemap.cpp src/generated/rpg_troop.cpp src/generated/rpg_troopmember.cpp src/generated/rpg_trooppage.cpp src/generated/rpg_trooppagecondition.cpp src/generated/rpg_variable.cpp ) set(LCF_HEADERS src/lcf/context.h src/lcf/dbarray.h src/lcf/dbarrayalloc.h src/lcf/dbbitarray.h src/lcf/dbstring.h src/lcf/encoder.h src/lcf/enum_tags.h src/lcf/flag_set.h src/lcf/ldb/reader.h src/lcf/lmt/reader.h src/lcf/lmu/reader.h src/lcf/log_handler.h src/lcf/lsd/reader.h src/lcf/reader_lcf.h src/lcf/reader_util.h src/lcf/reader_xml.h src/lcf/saveopt.h src/lcf/scope_guard.h src/lcf/span.h src/lcf/string_view.h src/lcf/writer_lcf.h src/lcf/writer_xml.h src/generated/lcf/ldb/chunks.h src/generated/lcf/lmt/chunks.h src/generated/lcf/lmu/chunks.h src/generated/lcf/lsd/chunks.h src/generated/lcf/rpg/actor.h src/generated/lcf/rpg/animation.h src/generated/lcf/rpg/animationcelldata.h src/generated/lcf/rpg/animationframe.h src/generated/lcf/rpg/animationtiming.h src/generated/lcf/rpg/attribute.h src/generated/lcf/rpg/battlecommand.h src/generated/lcf/rpg/battlecommands.h src/generated/lcf/rpg/battleranimation.h src/generated/lcf/rpg/battleranimationitemskill.h src/generated/lcf/rpg/battleranimationpose.h src/generated/lcf/rpg/battleranimationweapon.h src/generated/lcf/rpg/chipset.h src/generated/lcf/rpg/class.h src/generated/lcf/rpg/commonevent.h src/generated/lcf/rpg/database.h src/generated/lcf/rpg/encounter.h src/generated/lcf/rpg/enemy.h src/generated/lcf/rpg/enemyaction.h src/generated/lcf/rpg/equipment.h src/generated/lcf/rpg/event.h src/generated/lcf/rpg/eventcommand.h src/generated/lcf/rpg/eventpage.h src/generated/lcf/rpg/eventpagecondition.h src/generated/lcf/rpg/fwd.h src/generated/lcf/rpg/item.h src/generated/lcf/rpg/learning.h src/generated/lcf/rpg/map.h src/generated/lcf/rpg/mapinfo.h src/generated/lcf/rpg/movecommand.h src/generated/lcf/rpg/moveroute.h src/generated/lcf/rpg/music.h src/generated/lcf/rpg/parameters.h src/generated/lcf/rpg/rect.h src/generated/lcf/rpg/save.h src/generated/lcf/rpg/saveactor.h src/generated/lcf/rpg/savecommonevent.h src/generated/lcf/rpg/saveeasyrpgdata.h src/generated/lcf/rpg/saveeasyrpgtext.h src/generated/lcf/rpg/saveeasyrpgwindow.h src/generated/lcf/rpg/saveeventexecframe.h src/generated/lcf/rpg/saveeventexecstate.h src/generated/lcf/rpg/saveinventory.h src/generated/lcf/rpg/savemapevent.h src/generated/lcf/rpg/savemapeventbase.h src/generated/lcf/rpg/savemapinfo.h src/generated/lcf/rpg/savepanorama.h src/generated/lcf/rpg/savepartylocation.h src/generated/lcf/rpg/savepicture.h src/generated/lcf/rpg/savescreen.h src/generated/lcf/rpg/savesystem.h src/generated/lcf/rpg/savetarget.h src/generated/lcf/rpg/savetitle.h src/generated/lcf/rpg/savevehiclelocation.h src/generated/lcf/rpg/skill.h src/generated/lcf/rpg/sound.h src/generated/lcf/rpg/start.h src/generated/lcf/rpg/state.h src/generated/lcf/rpg/stringvariable.h src/generated/lcf/rpg/switch.h src/generated/lcf/rpg/system.h src/generated/lcf/rpg/terms.h src/generated/lcf/rpg/terrain.h src/generated/lcf/rpg/testbattler.h src/generated/lcf/rpg/treemap.h src/generated/lcf/rpg/troop.h src/generated/lcf/rpg/troopmember.h src/generated/lcf/rpg/trooppage.h src/generated/lcf/rpg/trooppagecondition.h src/generated/lcf/rpg/variable.h src/lcf/third_party/span.h ) set(LCF_SUPPORT_INI 0) if(LIBLCF_WITH_INI) list(APPEND LCF_SOURCES src/inireader.cpp ) list(APPEND LCF_HEADERS src/lcf/inireader.h ) set(LCF_SUPPORT_INI 1) endif() add_library(lcf ${LCF_SOURCES} ${LCF_HEADERS}) # IDE source grouping foreach(SG LDB LMT LMU LSD RPG THIRD_PARTY) string(TOLOWER ${SG} LSG) source_group("Source Files\\generated\\${SG}" REGULAR_EXPRESSION "generated/${LSG}_.*\\.cpp") source_group("Header Files\\generated\\${SG}" REGULAR_EXPRESSION "generated/lcf/${LSG}/.*\\.h") source_group("Source Files\\${SG}" REGULAR_EXPRESSION "${LSG}_.*\\.cpp") source_group("Header Files\\${SG}" REGULAR_EXPRESSION "/${LSG}/.*\\.h") endforeach() # includes include(GNUInstallDirs) target_include_directories( lcf PUBLIC $ $ $ $ ) # Optimize floating point math functions into intrinsics and don't check or set errno (i.e. sqrt(-1)) if (NOT CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") target_compile_options(lcf PRIVATE "-fno-math-errno") endif() # endianess checking if(${CMAKE_VERSION} VERSION_GREATER_EQUAL 3.20) if (CMAKE_CXX_BYTE_ORDER STREQUAL "BIG_ENDIAN") target_compile_definitions(lcf PRIVATE WORDS_BIGENDIAN=1) endif() else() include(TestBigEndian) test_big_endian(WORDS_BIGENDIAN) if(WORDS_BIGENDIAN) target_compile_definitions(lcf PRIVATE WORDS_BIGENDIAN=1) endif() endif() # Add optional library name postfix set_property(TARGET lcf PROPERTY DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}") # Export symbols for DLL set_property(TARGET lcf PROPERTY WINDOWS_EXPORT_ALL_SYMBOLS ON) # Name of the exported library set_property(TARGET lcf PROPERTY EXPORT_NAME liblcf) # inih if (LCF_SUPPORT_INI) find_package(inih REQUIRED) target_link_libraries(lcf inih::inih) else() message(STATUS "inih is disabled. This component is required when building EasyRPG Player.") endif () # icu set(LCF_SUPPORT_ICU 0) if(LIBLCF_WITH_ICU) find_package(ICU COMPONENTS i18n uc data) if(ICU_FOUND) target_link_libraries(lcf ICU::i18n ICU::uc ICU::data) list(APPEND LIBLCF_DEPS "icu-i18n") set(LCF_SUPPORT_ICU 1) else() if(NOT WIN32) message(FATAL_ERROR "ICU not found. Use LCF_SUPPORT_ICU=0 to disable ICU support (not recommended).") endif() message(STATUS "ICU not found. Using the system library.") message(STATUS "This build will only work on Windows 10 Version 1903 (May 2019) and newer!") target_link_libraries(lcf icu) set(LCF_SUPPORT_ICU 2) list(APPEND LIBLCF_DEPS "icu") endif() endif() # expat set(LCF_SUPPORT_XML 0) if(LIBLCF_WITH_XML) find_package(expat CONFIG) if(expat_FOUND) target_link_libraries(lcf expat::expat) set(LCF_SUPPORT_XML 1) else() # Fallback to old expat detection find_package(EXPAT REQUIRED) target_link_libraries(lcf EXPAT::EXPAT) set(LCF_SUPPORT_XML 2) endif() list(APPEND LIBLCF_DEPS "expat") endif() # mime types if(LIBLCF_UPDATE_MIMEDB AND NOT CMAKE_CROSSCOMPILING) find_program(UPDATE_MIME_DATABASE update-mime-database) endif() configure_file("${CMAKE_CURRENT_SOURCE_DIR}/builds/config.h.in" "src/lcf/config.h" @ONLY) target_sources(lcf PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src/lcf/config.h) # .so version set_property(TARGET lcf PROPERTY SOVERSION 0) # installation if(LIBLCF_ENABLE_INSTALL) # pkg-config file generation set(LCF_LIBDIR ${CMAKE_INSTALL_LIBDIR}) if(IS_ABSOLUTE ${LCF_LIBDIR}) file(RELATIVE_PATH LCF_LIBDIR ${CMAKE_INSTALL_PREFIX} ${LCF_LIBDIR}) endif() set(LCF_INCLUDEDIR ${CMAKE_INSTALL_INCLUDEDIR}) if(IS_ABSOLUTE ${LCF_INCLUDEDIR}) file(RELATIVE_PATH LCF_INCLUDEDIR ${CMAKE_INSTALL_PREFIX} ${LCF_INCLUDEDIR}) endif() set(PACKAGE_TARNAME ${PROJECT_NAME}) set(PACKAGE_VERSION ${PROJECT_VERSION}) set(prefix "${CMAKE_INSTALL_PREFIX}") set(exec_prefix "\${prefix}") set(libdir "\${exec_prefix}/${LCF_LIBDIR}") set(includedir "\${prefix}/${LCF_INCLUDEDIR}") string(REPLACE ";" " " AX_PACKAGE_REQUIRES_PRIVATE "${LIBLCF_DEPS}") configure_file(builds/${PROJECT_NAME}.pc.in builds/${PROJECT_NAME}.pc @ONLY) # Cmake-config file generation install( TARGETS lcf EXPORT lcf-export ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) set(LCF_INSTALL_HEADERS ${LCF_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/src/lcf/config.h) foreach(S ldb lmt lmu lsd rpg third_party) set(SUBDIR_HEADERS ${LCF_INSTALL_HEADERS}) list(FILTER SUBDIR_HEADERS INCLUDE REGEX "/${S}/") install(FILES ${SUBDIR_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lcf/${S}) list(REMOVE_ITEM LCF_INSTALL_HEADERS ${SUBDIR_HEADERS}) endforeach() install(FILES ${LCF_INSTALL_HEADERS} DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/lcf) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/builds/${PROJECT_NAME}.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig ) install( EXPORT lcf-export FILE liblcf-targets.cmake NAMESPACE liblcf:: DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/liblcf ) include(CMakePackageConfigHelpers) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/builds/cmake/liblcf-config.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/liblcf-config.cmake INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/liblcf ) write_basic_package_version_file( ${CMAKE_CURRENT_BINARY_DIR}/liblcf-config-version.cmake COMPATIBILITY ExactVersion ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/liblcf-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/liblcf-config-version.cmake ${CMAKE_CURRENT_SOURCE_DIR}/builds/cmake/Modules/Findinih.cmake DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/liblcf ) # mime types install( FILES ${CMAKE_CURRENT_SOURCE_DIR}/mime/${PROJECT_NAME}.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages ) if(LIBLCF_UPDATE_MIMEDB AND UPDATE_MIME_DATABASE) install(CODE "execute_process(COMMAND ${UPDATE_MIME_DATABASE} \$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_DATADIR}/mime)" ) endif() endif() # tests if(LIBLCF_ENABLE_TESTS) file(GLOB TEST_FILES ${CMAKE_CURRENT_SOURCE_DIR}/tests/*.cpp) add_executable(test_runner_lcf EXCLUDE_FROM_ALL ${TEST_FILES}) target_compile_definitions(test_runner_lcf PRIVATE DOCTEST_CONFIG_TREAT_CHAR_STAR_AS_STRING=1) set_target_properties(test_runner_lcf PROPERTIES OUTPUT_NAME "test_runner") target_link_libraries(test_runner_lcf lcf) add_custom_target(check_lcf COMMAND test_runner_lcf) if(NOT TARGET check) add_custom_target(check) endif() add_dependencies(check_lcf test_runner_lcf) add_dependencies(check check_lcf) endif() # benchmarks if(LIBLCF_ENABLE_BENCHMARKS) file(GLOB BENCH_FILES ${CMAKE_CURRENT_SOURCE_DIR}/bench/*.cpp) foreach(i ${BENCH_FILES}) get_filename_component(name "${i}" NAME_WE) add_executable(bench_${name} ${i}) target_link_libraries(bench_${name} lcf) endforeach() endif() # tools if(LIBLCF_ENABLE_TOOLS) add_custom_target(tools) add_dependencies(tools lcf) list(APPEND TOOLS lcfstrings) if(LIBLCF_WITH_XML) list(APPEND TOOLS lcf2xml) endif() foreach(tool ${TOOLS}) add_executable(${tool} tools/${tool}.cpp) target_link_libraries(${tool} lcf) add_dependencies(tools ${tool}) if(LIBLCF_ENABLE_INSTALL) install(TARGETS ${tool} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() endforeach() endif() # Doxygen documentation find_package(Doxygen) if(DOXYGEN_FOUND) add_custom_target(liblcf_doc ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/builds/Doxyfile DEPENDS lcf WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/builds COMMENT "Generating API documentation with Doxygen" VERBATIM) else() message(STATUS "This means no API documentation is generated.") endif()