cmake_minimum_required(VERSION 3.23.0) if(POLICY CMP0135) cmake_policy(SET CMP0135 NEW) endif() project(Jinja2Cpp VERSION 1.3.2) if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}") set(JINJA2CPP_IS_MAIN_PROJECT TRUE) else() set(JINJA2CPP_IS_MAIN_PROJECT FALSE) endif() # Options set(JINJA2CPP_SANITIZERS address+undefined memory) set(JINJA2CPP_WITH_SANITIZERS none CACHE STRING "Build with sanitizer") set_property(CACHE JINJA2CPP_WITH_SANITIZERS PROPERTY STRINGS ${JINJA2CPP_SANITIZERS}) set(JINJA2CPP_SUPPORTED_REGEX std boost) set(JINJA2CPP_USE_REGEX boost CACHE STRING "Use regex parser in lexer, boost works faster on most platforms") set_property(CACHE JINJA2CPP_USE_REGEX PROPERTY STRINGS ${JINJA2CPP_SUPPORTED_REGEX}) set(JINJA2CPP_WITH_JSON_BINDINGS boost nlohmann rapid all none) set(JINJA2CPP_WITH_JSON_BINDINGS boost CACHE STRING "Build with json support(boost|rapid)") set_property(CACHE JINJA2CPP_WITH_JSON_BINDINGS PROPERTY STRINGS ${JINJA2CPP_WITH_JSON_BINDINGS}) set (JINJA2CPP_DEPS_MODE "internal" CACHE STRING "Jinja2Cpp dependency management mode (internal | external | external-boost | conan-build). See documentation for details. 'interal' is default.") option(JINJA2CPP_BUILD_TESTS "Build Jinja2Cpp unit tests" ${JINJA2CPP_IS_MAIN_PROJECT}) option(JINJA2CPP_STRICT_WARNINGS "Enable additional warnings and treat them as errors" ON) option(JINJA2CPP_BUILD_SHARED "Build shared linkage version of Jinja2Cpp" OFF) option(JINJA2CPP_PIC "Control -fPIC option for library build" OFF) option(JINJA2CPP_VERBOSE "Add extra debug output to the build scripts" OFF) option(JINJA2CPP_INSTALL "Add installation rules for JinjaCpp targets" ${JINJA2CPP_IS_MAIN_PROJECT}) if (DEFINED BUILD_SHARED_LIBS) set(JINJA2CPP_BUILD_SHARED ${BUILD_SHARED_LIBS}) endif () if (JINJA2CPP_BUILD_SHARED) set(JINJA2CPP_PIC ON) set(JINJA2CPP_MSVC_RUNTIME_TYPE "/MD") endif () if (NOT JINJA2CPP_DEPS_MODE) set(JINJA2CPP_DEPS_MODE "internal") endif () if (JINJA2CPP_IS_MAIN_PROJECT OR NOT CMAKE_CXX_STANDARD) set(JINJA2CPP_CXX_STANDARD 14 CACHE STRING "Jinja2Cpp C++ standard to build with. C++14 is default") set(CMAKE_CXX_STANDARD ${JINJA2CPP_CXX_STANDARD}) endif () if (NOT JINJA2CPP_CXX_STANDARD) set (JINJA2CPP_CXX_STANDARD ${CMAKE_CXX_STANDARD}) endif () if (JINJA2CPP_CXX_STANDARD LESS 14) message(FATAL_ERROR "Jinja2Cpp is required C++14 or greater standard set. Currently selected standard: ${JINJA2CPP_CXX_STANDARD}") else () message(STATUS "Jinja2Cpp C++ standard: ${JINJA2CPP_CXX_STANDARD}") endif () include(CMakePackageConfigHelpers) include(GNUInstallDirs) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") set(CLANG_CXX_FLAGS) set(GCC_CXX_FLAGS) set(MSVC_CXX_FLAGS) if (JINJA2CPP_WITH_COVERAGE) message(STATUS "This is DEBUG build with enabled Code Coverage") set(CMAKE_BUILD_TYPE Debug) set(JINJA2CPP_COVERAGE_TARGET "jinja2cpp_build_coverage") include(coverage) add_coverage_target("${JINJA2CPP_COVERAGE_TARGET}") endif () if(NOT ${JINJA2CPP_WITH_SANITIZERS} STREQUAL "none") message (STATUS "Build with sanitizers enabled: ${JINJA2CPP_WITH_SANITIZERS}") set(_chosen_san) list(FIND JINJA2CPP_SANITIZERS ${JINJA2CPP_WITH_SANITIZERS} _chosen_san) if (${_chosen_san} EQUAL -1) message(FATAL_ERROR "Wrong sanitizer type has been chosen, must be one of ${JINJA2CPP_SANITIZERS}") endif() include("sanitizer.${JINJA2CPP_WITH_SANITIZERS}") set (JINJA2CPP_SANITIZE_TARGET "jinja2cpp_build_sanitizers") add_sanitizer_target(${JINJA2CPP_SANITIZE_TARGET}) endif() if (UNIX) if (JINJA2CPP_PIC OR CONAN_CMAKE_POSITION_INDEPENDENT_CODE) add_compile_options(-fPIC) endif () if (DEFINED CONAN_SHARED_LINKER_FLAGS) set(GCC_CXX_FLAGS ${GCC_CXX_FLAGS} -Wl,${CONAN_SHARED_LINKER_FLAGS}) set(CLANG_CXX_FLAGS ${CLANG_CXX_FLAGS} -Wl,${CONAN_SHARED_LINKER_FLAGS}) endif () else () set(GCC_CXX_FLAGS ${GCC_CXX_FLAGS} "-Wa,-mbig-obj" -O1) if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") add_definitions(-D_CRT_SECURE_NO_WARNINGS) endif () add_definitions(-DBOOST_ALL_NO_LIB) set(MSVC_CXX_FLAGS ${MSVC_CXX_FLAGS} /wd4503 /bigobj) if (CMAKE_BUILD_TYPE MATCHES "Debug" AND JINJA2CPP_MSVC_RUNTIME_TYPE) set(JINJA2CPP_MSVC_RUNTIME_TYPE "${JINJA2CPP_MSVC_RUNTIME_TYPE}d") endif () if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") if (JINJA2CPP_DEPS_MODE MATCHES "conan-build" OR CMAKE_BUILD_TYPE STREQUAL "") if (NOT JINJA2CPP_MSVC_RUNTIME_TYPE STREQUAL "") set(MSVC_RUNTIME_DEBUG ${JINJA2CPP_MSVC_RUNTIME_TYPE}) set(MSVC_RUNTIME_RELEASE ${JINJA2CPP_MSVC_RUNTIME_TYPE}) endif () set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${MSVC_RUNTIME_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MSVC_RUNTIME_RELEASE}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${MSVC_RUNTIME_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/PROFILE") set(Boost_USE_DEBUG_RUNTIME OFF) elseif (CMAKE_BUILD_TYPE MATCHES "Debug") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${JINJA2CPP_MSVC_RUNTIME_TYPE}") set(Boost_USE_DEBUG_RUNTIME ON) else () set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${JINJA2CPP_MSVC_RUNTIME_TYPE}") set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} ${JINJA2CPP_MSVC_RUNTIME_TYPE}") set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/PROFILE") set(Boost_USE_DEBUG_RUNTIME OFF) endif () message(STATUS "Selected MSVC runtime type for Jinja2C++ library: '${JINJA2CPP_MSVC_RUNTIME_TYPE}'") endif () endif() if (JINJA2CPP_BUILD_SHARED) set(LIB_LINK_TYPE SHARED) message(STATUS "Jinja2C++ library type: SHARED") else() set(LIB_LINK_TYPE STATIC) message(STATUS "Jinja2C++ library type: STATIC") endif() include(collect_sources) set (LIB_TARGET_NAME jinja2cpp) CollectSources(Sources Headers ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/src) CollectSources(PublicSources PublicHeaders ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) add_library(${LIB_TARGET_NAME} ${LIB_LINK_TYPE} ${Sources} ${Headers} ${PublicHeaders} ) target_sources(${LIB_TARGET_NAME} PUBLIC FILE_SET HEADERS FILES ${PublicHeaders} BASE_DIRS include ) string(TOUPPER "${CMAKE_BUILD_TYPE}" BUILD_CFG_NAME) set(CURRENT_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CMAKE_CXX_FLAGS_${BUILD_CFG_NAME}}") set(JINJA2CPP_EXTRA_LIBS "" CACHE STRING "You can pass some libs that could used during link stage") set(JINJA2CPP_PUBLIC_LIBS "${JINJA2CPP_EXTRA_LIBS}") separate_arguments(JINJA2CPP_PUBLIC_LIBS) if (JINJA2CPP_WITH_COVERAGE) target_compile_options( ${JINJA2CPP_COVERAGE_TARGET} INTERFACE -g -O0 ) list(APPEND JINJA2CPP_PUBLIC_LIBS ${JINJA2CPP_COVERAGE_TARGET}) endif() if (NOT JINJA2CPP_WITH_SANITIZERS STREQUAL "none") target_compile_options( ${JINJA2CPP_SANITIZE_TARGET} INTERFACE -g -O2 ) list(APPEND JINJA2CPP_PUBLIC_LIBS ${JINJA2CPP_SANITIZE_TARGET}) endif() set(JINJA2CPP_PRIVATE_LIBS "${JINJA2CPP_PRIVATE_LIBS}") include(thirdparty/CMakeLists.txt) target_link_libraries( ${LIB_TARGET_NAME} PUBLIC ${JINJA2CPP_PUBLIC_LIBS} PRIVATE ${JINJA2CPP_PRIVATE_LIBS} ) target_include_directories(${LIB_TARGET_NAME} PUBLIC $ $ ) if (JINJA2CPP_STRICT_WARNINGS) if (UNIX) set(GCC_CXX_FLAGS ${GCC_CXX_FLAGS} -Wall -Werror) set(CLANG_CXX_FLAGS ${CLANG_CXX_FLAGS} -Wall -Werror -Wno-unused-command-line-argument) set(MSVC_CXX_FLAGS ${MSVC_CXX_FLAGS} /W4) endif () endif () if (CMAKE_CXX_COMPILER_ID MATCHES "GNU") target_compile_options(${LIB_TARGET_NAME} PRIVATE ${GCC_CXX_FLAGS}) elseif (CMAKE_CXX_COMPILER_ID MATCHES "Clang") target_compile_options(${LIB_TARGET_NAME} PRIVATE ${CLANG_CXX_FLAGS}) elseif (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") target_compile_options(${LIB_TARGET_NAME} PRIVATE ${MSVC_CXX_FLAGS}) endif () if ("${JINJA2CPP_USE_REGEX}" STREQUAL "boost") set(_regex_define "-DJINJA2CPP_USE_REGEX_BOOST") endif() if ("${JINJA2CPP_WITH_JSON_BINDINGS}" STREQUAL "boost") set(_bindings_define "-DJINJA2CPP_WITH_JSON_BINDINGS_BOOST") elseif("${JINJA2CPP_WITH_JSON_BINDINGS}" STREQUAL "rapid") set(_bindings_define "-DJINJA2CPP_WITH_JSON_BINDINGS_RAPID") endif() target_compile_definitions(${LIB_TARGET_NAME} PUBLIC -DBOOST_SYSTEM_NO_DEPRECATED -DBOOST_ERROR_CODE_HEADER_ONLY ${_regex_define} ${_bindings_define} ) if (JINJA2CPP_BUILD_SHARED) target_compile_definitions(${LIB_TARGET_NAME} PRIVATE -DJINJA2CPP_BUILD_AS_SHARED PUBLIC -DJINJA2CPP_LINK_AS_SHARED) endif () set_target_properties(${LIB_TARGET_NAME} PROPERTIES VERSION ${PROJECT_VERSION} SOVERSION 1 ) set_target_properties(${LIB_TARGET_NAME} PROPERTIES CXX_STANDARD ${JINJA2CPP_CXX_STANDARD} CXX_STANDARD_REQUIRED ON ) configure_file(jinja2cpp.pc.in ${CMAKE_BINARY_DIR}/jinja2cpp.pc @ONLY) if (JINJA2CPP_BUILD_TESTS) enable_testing() CollectSources(TestSources TestHeaders ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/test) add_executable(jinja2cpp_tests ${TestSources} ${TestHeaders}) target_link_libraries(jinja2cpp_tests gtest gtest_main nlohmann_json::nlohmann_json ${LIB_TARGET_NAME} ${EXTRA_TEST_LIBS} ${JINJA2CPP_PRIVATE_LIBS}) set_target_properties(jinja2cpp_tests PROPERTIES CXX_STANDARD ${JINJA2CPP_CXX_STANDARD} CXX_STANDARD_REQUIRED ON) if (CMAKE_CXX_COMPILER_ID MATCHES "MSVC") target_compile_options(jinja2cpp_tests PRIVATE /bigobj) endif () add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/test_data/simple_template1.j2tpl COMMAND ${CMAKE_COMMAND} ARGS -E copy_directory ${CMAKE_CURRENT_SOURCE_DIR}/test/test_data ${CMAKE_CURRENT_BINARY_DIR}/test_data MAIN_DEPENDENCY ${CMAKE_CURRENT_SOURCE_DIR}/test/test_data/simple_template1.j2tpl COMMENT "Copy test data to the destination dir" ) add_custom_target(CopyTestData ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/test_data/simple_template1.j2tpl ) add_dependencies(jinja2cpp_tests CopyTestData) add_test(NAME jinja2cpp_tests COMMAND jinja2cpp_tests) endif () set (JINJA2CPP_INSTALL_CONFIG_DIR "${CMAKE_INSTALL_LIBDIR}/${LIB_TARGET_NAME}") set (JINJA2CPP_TMP_CONFIG_PATH "cmake/config") macro (Jinja2CppGetTargetIncludeDir infix target) message (STATUS "infix: ${infix} target: ${target}") if (TARGET ${target}) set (_J2CPP_VAR_NAME JINJA2CPP_${infix}_INCLUDE_DIRECTORIES) get_target_property(${_J2CPP_VAR_NAME} ${target} INTERFACE_INCLUDE_DIRECTORIES) else () message(WARNING "No target: ${target}") endif() endmacro () Jinja2CppGetTargetIncludeDir(EXPECTED-LITE nonstd::expected-lite) Jinja2CppGetTargetIncludeDir(VARIANT-LITE nonstd::variant-lite) Jinja2CppGetTargetIncludeDir(OPTIONAL-LITE nonstd::optional-lite) Jinja2CppGetTargetIncludeDir(STRING-VIEW-LITE nonstd::string-view-lite) # Workaround for #14444 bug of CMake (https://gitlab.kitware.com/cmake/cmake/issues/14444) # We can't use EXPORT feature of 'install' as is due to limitation of subproject's targets installation # So jinja2cpp-config.cmake should be written manually if(JINJA2CPP_INSTALL) install( TARGETS ${LIB_TARGET_NAME} EXPORT InstallTargets RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}/static FILE_SET HEADERS ) install( FILES ${CMAKE_BINARY_DIR}/jinja2cpp.pc DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/pkgconfig ) install( EXPORT InstallTargets FILE jinja2cpp-cfg.cmake DESTINATION ${JINJA2CPP_INSTALL_CONFIG_DIR} ) configure_package_config_file( cmake/public/jinja2cpp-config.cmake.in ${JINJA2CPP_TMP_CONFIG_PATH}/jinja2cpp-config.cmake INSTALL_DESTINATION ${JINJA2CPP_TMP_CONFIG_PATH} NO_CHECK_REQUIRED_COMPONENTS_MACRO ) configure_package_config_file( cmake/public/jinja2cpp-config-deps-${JINJA2CPP_DEPS_MODE}.cmake.in ${JINJA2CPP_TMP_CONFIG_PATH}/jinja2cpp-config-deps.cmake INSTALL_DESTINATION ${JINJA2CPP_TMP_CONFIG_PATH} NO_CHECK_REQUIRED_COMPONENTS_MACRO ) install( FILES ${CMAKE_CURRENT_BINARY_DIR}/${JINJA2CPP_TMP_CONFIG_PATH}/${LIB_TARGET_NAME}-config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${JINJA2CPP_TMP_CONFIG_PATH}/${LIB_TARGET_NAME}-config-deps.cmake DESTINATION ${JINJA2CPP_INSTALL_CONFIG_DIR} ) endif()