# This is the top-level CMakeLists.txt file for the Clazy project. # # To build the man page from POD, run 'make man' after CMake (assumes perl is available) # To install the resulting man page, run 'make install' # The man page is not available on Windows. # cmake_minimum_required(VERSION 3.7) project(clazy) if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.12.0") cmake_policy(SET CMP0074 NEW) endif() include(FeatureSummary) include(GenerateExportHeader) include(GNUInstallDirs) # Version setup set(CLAZY_VERSION_MAJOR "1") set(CLAZY_VERSION_MINOR "12") set(CLAZY_VERSION_PATCH "0") set(CLAZY_VERSION "${CLAZY_VERSION_MAJOR}.${CLAZY_VERSION_MINOR}.${CLAZY_VERSION_PATCH}") set(CLAZY_PRINT_VERSION "${CLAZY_VERSION_MAJOR}.${CLAZY_VERSION_MINOR}") set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_LIST_DIR}/cmake) if (NOT CLAZY_BUILD_WITH_CLANG) find_package(Clang 11.0 MODULE REQUIRED) if (CLANG_CLANG-CPP_LIB AND NOT APPLE) set(default_use_clang_cpp ON) else() set(default_use_clang_cpp OFF) endif() option(CLAZY_LINK_CLANG_DYLIB "Link clazy to dynamic Clang C++ library clang-cpp." ${default_use_clang_cpp}) endif() set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib) add_definitions(-D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS) add_definitions(-D_GNU_SOURCE -DHAVE_CLANG_CONFIG_H) option(CLAZY_AST_MATCHERS_CRASH_WORKAROUND "Disable AST Matchers if being built with clang. See bug #392223" ON) option(LINK_CLAZY_TO_LLVM "Links the clazy plugin to LLVM. Switch to OFF if your clang binary has all symbols already. Might need to be OFF if your LLVM is static." ON) option(APPIMAGE_HACK "Links the clazy plugin to the clang tooling libs only. For some reason this is needed when building on our old CentOS 6.8 to create the AppImage." OFF) option(CLAZY_MAN_PAGE "Builds the man page." ON) option(CLAZY_ENABLE_SANITIZERS "Builds clazy with ASAN/UBSAN. For clazy's own development only." OFF) if (CLAZY_ENABLE_SANITIZERS) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") if (NOT MSVC) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") endif() endif() if (CLAZY_AST_MATCHERS_CRASH_WORKAROUND AND "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 7.0 AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS 8.0) message("Enabling AST Matchers workaround. Consider updating clang or building with gcc instead. See bug #392223.") add_definitions(-DCLAZY_DISABLE_AST_MATCHERS) endif() if(NOT CLAZY_BUILD_WITH_CLANG AND MSVC AND NOT CLANG_LIBRARY_IMPORT) message(FATAL_ERROR "\nOn MSVC you need to pass -DCLANG_LIBRARY_IMPORT=C:/path/to/llvm-build/lib/clang.lib to cmake when building Clazy.\nAlso make sure you've built LLVM with -DLLVM_EXPORT_SYMBOLS_FOR_PLUGINS=ON") endif() if(MSVC) # disable trigger-happy warnings from Clang/LLVM headers set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /wd4267 /wd4244 /wd4291 /wd4800 /wd4141 /wd4146 /wd4251") elseif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_CXX_COMPILER_ID MATCHES "Clang") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-common -Woverloaded-virtual -Wcast-qual -fno-strict-aliasing -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings -fno-exceptions -fno-rtti") endif() set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-flat_namespace -Wl,-undefined -Wl,suppress") if(WIN32) add_definitions(-D_CRT_SECURE_NO_WARNINGS) else() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC") endif() set(CMAKE_CXX_STANDARD 17) set(CXX_STANDARD_REQUIRED ON) # Look for std::regex support if(NOT DEFINED REGEX_RUN_RESULT) message("Looking for std::regex support...") try_compile(REGEX_RUN_RESULT ${CMAKE_CURRENT_BINARY_DIR} SOURCES ${CMAKE_CURRENT_LIST_DIR}/.cmake_has_regex_test.cpp) endif() if(NOT DEFINED REGEX_RUN_RESULT) message(FATAL_ERROR "std::regex support is mndatory") endif() # Compiler might support c++17 but not have std::filesystem in the standard library if (NOT FILESYSTEM_RUN_RESULT) try_compile(FILESYSTEM_RUN_RESULT ${CMAKE_CURRENT_BINARY_DIR} SOURCES ${CMAKE_CURRENT_LIST_DIR}/.cmake_has_filesystem_test.cpp OUTPUT_VARIABLE foo CXX_STANDARD 17 CXX_STANDARD_REQUIRED true) endif() if (NOT FILESYSTEM_RUN_RESULT) message(FATAL_ERROR "std::filesystem support is mndatory") endif() include(ClazySources.cmake) include_directories(${CMAKE_BINARY_DIR}) include_directories(${CLANG_INCLUDE_DIRS} ${CMAKE_CURRENT_LIST_DIR} ${CMAKE_CURRENT_LIST_DIR}/src) link_directories("${LLVM_INSTALL_PREFIX}/lib" ${LLVM_LIBRARY_DIRS}) set(clang_tooling_refactoring_lib clangToolingRefactoring) if (${LLVM_VERSION} VERSION_GREATER_EQUAL "15.0.0") set(clang_support_lib clangSupport) endif() macro(link_to_llvm name is_standalone) if (CLAZY_LINK_CLANG_DYLIB) target_link_libraries(${name} clang-cpp) else() foreach(clang_lib ${CLANG_LIBS}) if(MSVC) get_filename_component(LIB_FILENAME ${clang_lib} NAME) if(LIB_FILENAME STREQUAL "clangFrontend.lib") # On MSVC we don't link against clangFrontend.lib, instead we link against clang.exe (via clang.lib) # Otherwise the clazy plugin would have it's own plugin registry and clang wouldn't see it. # This way clazy registers with clang. continue() endif() endif() target_link_libraries(${name} ${clang_lib}) endforeach() target_link_libraries(${name} ${clang_support_lib}) target_link_libraries(${name} clangTooling) target_link_libraries(${name} clangToolingCore) target_link_libraries(${name} ${clang_tooling_refactoring_lib}) endif() foreach(llvm_lib ${LLVM_LIBS}) if(NOT ${is_standalone} AND NOT APPLE AND NOT MINGW AND NOT MSVC) ## Don't link against LLVMSupport, causes: CommandLine Error: Option 'view-background' registered more than once! if (NOT llvm_lib MATCHES ".*LLVMSupport.*") target_link_libraries(${name} ${llvm_lib}) endif() else() target_link_libraries(${name} ${llvm_lib}) endif() endforeach() foreach(user_lib ${USER_LIBS}) target_link_libraries(${name} ${user_lib}) endforeach() foreach(llvm_system_lib ${LLVM_SYSTEM_LIBS}) target_link_libraries(${name} ${llvm_system_lib}) endforeach() if(WIN32) target_link_libraries(${name} version.lib) endif() endmacro() macro(add_clang_plugin name) set(srcs ${ARGN}) add_library(${name} SHARED ${srcs}) if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.16.0") # 30% speedup target_precompile_headers(${name} PRIVATE src/checkbase.h) endif() if(SYMBOL_FILE) set_target_properties(${name} PROPERTIES LINK_FlAGS "-exported_symbols_list ${SYMBOL_FILE}") endif() if (LINK_CLAZY_TO_LLVM) link_to_llvm(${name} FALSE) else() if (APPIMAGE_HACK) # Hack to build on old CentOS 6.8 target_link_libraries(${name} clangTooling) target_link_libraries(${name} clangToolingCore) target_link_libraries(${name} ${clang_tooling_refactoring_lib}) endif() endif() if(MSVC) target_link_libraries(${name} ${CLANG_LIBRARY_IMPORT}) # Link against clang.exe to share the plugin registry endif() endmacro() set(SYMBOL_FILE Lazy.exports) if (NOT CLAZY_BUILD_WITH_CLANG) set(CLAZY_MINI_AST_DUMPER_SRCS src/MiniAstDumper.cpp) add_clang_plugin(ClazyPlugin ${CLAZY_PLUGIN_SRCS} ${CLAZY_MINI_AST_DUMPER_SRCS}) set_target_properties(ClazyPlugin PROPERTIES LINKER_LANGUAGE CXX PREFIX "" ) install(TARGETS ClazyPlugin RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) if(NOT WIN32) if(APPLE) find_program(READLINK_CMD greadlink) else() find_program(READLINK_CMD readlink) endif() if(NOT READLINK_CMD) message(FATAL_ERROR "Could not find a proper readlink. On Mac OSX you should install coreutils using homebrew in order to use the GNU readlink") endif() file(RELATIVE_PATH BIN_RELATIVE_LIBDIR "${CMAKE_INSTALL_FULL_BINDIR}" "${CMAKE_INSTALL_FULL_LIBDIR}") file(RELATIVE_PATH BIN_RELATIVE_SHAREDIR "${CMAKE_INSTALL_FULL_BINDIR}" "${CMAKE_INSTALL_FULL_DATAROOTDIR}") configure_file(${CMAKE_CURRENT_LIST_DIR}/clazy.cmake ${CMAKE_BINARY_DIR}/clazy @ONLY) install(PROGRAMS ${CMAKE_BINARY_DIR}/clazy DESTINATION bin) else() install(PROGRAMS ${CMAKE_CURRENT_LIST_DIR}/clazy.bat DESTINATION ${CMAKE_INSTALL_BINDIR}) if(MSVC) install(PROGRAMS ${CMAKE_CURRENT_LIST_DIR}/clazy-cl.bat DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() endif() # Install the explanation README's include(${CMAKE_CURRENT_LIST_DIR}/readmes.cmake) install(FILES ${README_LEVEL0_FILES} DESTINATION ${CMAKE_INSTALL_DOCDIR}/level0) install(FILES ${README_LEVEL1_FILES} DESTINATION ${CMAKE_INSTALL_DOCDIR}/level1) install(FILES ${README_LEVEL2_FILES} DESTINATION ${CMAKE_INSTALL_DOCDIR}/level2) install(FILES ${README_manuallevel_FILES} DESTINATION ${CMAKE_INSTALL_DOCDIR}/manuallevel) # Install more doc files install(FILES README.md LICENSES/LGPL-2.0-or-later.txt checks.json DESTINATION ${CMAKE_INSTALL_DOCDIR}) # Build docs if (CLAZY_MAN_PAGE) add_subdirectory(docs) endif() # rpath set(CMAKE_SKIP_BUILD_RPATH FALSE) set(CMAKE_BUILD_WITH_INSTALL_RPATH FALSE) set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") set(CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE) list(FIND CMAKE_PLATFORM_IMPLICIT_LINK_DIRECTORIES "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" isSystemDir) if("${isSystemDir}" STREQUAL "-1") set(CMAKE_INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}") endif("${isSystemDir}" STREQUAL "-1") # Build clazy-standalone add_executable(clazy-standalone ${CLAZY_STANDALONE_SRCS}) if(MSVC) # On MSVC clang-standalone crashes with a meaningless backtrace if linked to ClazyPlugin.dll target_link_libraries(clazy-standalone clangFrontend) else() target_link_libraries(clazy-standalone ClazyPlugin) endif() link_to_llvm(clazy-standalone TRUE) install(TARGETS clazy-standalone DESTINATION bin PERMISSIONS OWNER_WRITE OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE) set(CPACK_PACKAGE_VERSION_MAJOR ${CLAZY_VERSION_MAJOR}) set(CPACK_PACKAGE_VERSION_MINOR ${CLAZY_VERSION_MINOR}) set(CPACK_PACKAGE_VERSION_PATCH ${CLAZY_VERSION_PATCH}) include(CPack) else() set(LLVM_LINK_COMPONENTS Support ) add_clang_library(clazyPlugin ${CLAZY_PLUGIN_SRCS} LINK_LIBS clangToolingCore clangToolingInclusions ${clang_tooling_refactoring_lib} clangFrontend clangDriver clangCodeGen clangSema clangAnalysis clangRewriteFrontend clangRewrite clangAST clangASTMatchers clangParse clangLex clangBasic clangARCMigrate clangEdit clangFrontendTool clangRewrite clangSerialization ${clang_support_lib} clangTooling clangStaticAnalyzerCheckers clangStaticAnalyzerCore clangStaticAnalyzerFrontend ) add_executable(clazy-standalone ${CLAZY_STANDALONE_SRCS}) target_link_libraries(clazy-standalone clazyPlugin) install(TARGETS clazy-standalone DESTINATION bin PERMISSIONS OWNER_WRITE OWNER_EXECUTE OWNER_READ GROUP_EXECUTE GROUP_READ WORLD_READ WORLD_EXECUTE) endif() function(to_raw_string_literal input_string output_string) if (MSVC) # Work around "C2026: string too big, trailing characters truncated" # https://docs.microsoft.com/en-us/cpp/error-messages/compiler-errors-1/compiler-error-c2026?view=vs-2019 # The limit is 16380 single-byte characters, so split up the string as # suggested on the site. set(str ${input_string}) set(chunk_size 1000) set(result "\n") string(LENGTH ${str} str_size) while (${str_size} GREATER ${chunk_size}) string(SUBSTRING ${str} 0 ${chunk_size} chunk) string(SUBSTRING ${str} ${chunk_size} -1 str) set(chunk "R\"meta(${chunk})meta\"\n") string(APPEND result ${chunk}) string(LENGTH ${str} str_size) endwhile() if (str_size GREATER 0) string(APPEND result "R\"meta(${str})meta\"\n") endif() set(${output_string} ${result} PARENT_SCOPE) else() set(result "\nR\"meta(${input_string})meta\"\n") set(${output_string} ${result} PARENT_SCOPE) endif() endfunction() file(READ checks.json SUPPORTED_CHECKS_JSON_STR) to_raw_string_literal(${SUPPORTED_CHECKS_JSON_STR} SUPPORTED_CHECKS_JSON_STR) configure_file(checks.json.h.in checks.json.h) enable_testing() include(ClazyTests.generated.cmake) install(FILES org.kde.clazy.metainfo.xml DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo)