cmake_minimum_required(VERSION 3.10) project(armips) option(ARMIPS_PRECOMPILE_HEADERS "Use precompiled headers" OFF) option(ARMIPS_REGEXP "Enable regexp expression functions" ON) option(ARMIPS_USE_STD_FILESYSTEM "Use std::filesystem instead of third party implementation" OFF) option(ARMIPS_LIBRARY_ONLY "Build libarmips, skip building armips and armipstests binaries" OFF) macro(check_compiler VARIABLE NAME) if (${CMAKE_CXX_COMPILER_ID} MATCHES ${NAME}) set(${VARIABLE} TRUE) else() set(${VARIABLE} FALSE) endif() endmacro() check_compiler(CLANG "Clang") check_compiler(GCC "GNU") # Helper function to set common parameters for a target function(init_target TARGET_NAME) set_target_properties(${TARGET_NAME} PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED TRUE CXX_EXTENSIONS FALSE) target_include_directories(${TARGET_NAME} BEFORE PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) if (GCC OR CLANG) # clang-cl seems to treat -Wall as -Weverything if (NOT MSVC) target_compile_options(${TARGET_NAME} PRIVATE -Wall) endif() target_compile_options(${TARGET_NAME} PRIVATE -Wno-unused-parameter) if (NOT MSVC AND NOT ${CMAKE_SYSTEM_NAME} MATCHES "Haiku" AND NOT WIIU) find_package(Threads REQUIRED) target_link_libraries(${TARGET_NAME} PRIVATE Threads::Threads) endif() endif () if (ARMIPS_REGEXP) target_compile_definitions(${TARGET_NAME} PRIVATE ARMIPS_REGEXP=1) endif() if (WIN32) if (MSVC) target_compile_options(${TARGET_NAME} PRIVATE /Zc:__cplusplus) target_compile_options(${TARGET_NAME} PRIVATE /permissive-) target_compile_definitions(${TARGET_NAME} PRIVATE UNICODE _UNICODE) target_compile_definitions(${TARGET_NAME} PRIVATE _CRT_SECURE_NO_WARNINGS) else() target_compile_options(${TARGET_NAME} PRIVATE -municode) set_target_properties(${TARGET_NAME} PROPERTIES LINK_FLAGS "-municode") endif() endif() endfunction() # Helper function to automatically set source groups for all source files function(armips_target_sources TARGET SCOPE) target_sources("${TARGET}" "${SCOPE}" ${ARGN}) source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${ARGN}) endfunction() # tinyformat add_library(tinyformat INTERFACE) target_include_directories(tinyformat INTERFACE ext/tinyformat) # libarmips add_library(armips STATIC) init_target(armips) target_link_libraries(armips PUBLIC tinyformat) if (ARMIPS_USE_STD_FILESYSTEM) target_compile_definitions(armips PUBLIC ARMIPS_USE_STD_FILESYSTEM) else() add_subdirectory(ext/filesystem) target_link_libraries(armips PUBLIC ghc_filesystem) endif() if (WIN32) target_link_libraries(armips PUBLIC shlwapi) endif() armips_target_sources(armips PRIVATE Archs/Architecture.h Archs/Architecture.cpp Archs/ARM/Arm.cpp Archs/ARM/Arm.h Archs/ARM/ArmExpressionFunctions.cpp Archs/ARM/ArmExpressionFunctions.h Archs/ARM/ArmElfRelocator.cpp Archs/ARM/ArmElfRelocator.h Archs/ARM/ArmOpcodes.cpp Archs/ARM/ArmOpcodes.h Archs/ARM/ArmParser.cpp Archs/ARM/ArmParser.h Archs/ARM/CArmInstruction.cpp Archs/ARM/CArmInstruction.h Archs/ARM/CThumbInstruction.cpp Archs/ARM/CThumbInstruction.h Archs/ARM/Pool.cpp Archs/ARM/Pool.h Archs/ARM/ThumbOpcodes.cpp Archs/ARM/ThumbOpcodes.h Archs/MIPS/CMipsInstruction.cpp Archs/MIPS/CMipsInstruction.h Archs/MIPS/Mips.cpp Archs/MIPS/Mips.h Archs/MIPS/MipsElfFile.cpp Archs/MIPS/MipsElfFile.h Archs/MIPS/MipsExpressionFunctions.cpp Archs/MIPS/MipsExpressionFunctions.h Archs/MIPS/MipsElfRelocator.cpp Archs/MIPS/MipsElfRelocator.h Archs/MIPS/MipsMacros.cpp Archs/MIPS/MipsMacros.h Archs/MIPS/MipsOpcodes.cpp Archs/MIPS/MipsOpcodes.h Archs/MIPS/MipsParser.cpp Archs/MIPS/MipsParser.h Archs/MIPS/PsxRelocator.cpp Archs/MIPS/PsxRelocator.h Archs/SuperH/SuperH.cpp Archs/SuperH/SuperH.h Archs/SuperH/CShInstruction.cpp Archs/SuperH/CShInstruction.h Archs/SuperH/ShParser.cpp Archs/SuperH/ShParser.h Archs/SuperH/ShOpcodes.cpp Archs/SuperH/ShOpcodes.h Archs/SuperH/ShElfRelocator.cpp Archs/SuperH/ShElfRelocator.h Archs/SuperH/ShExpressionFunctions.cpp Archs/SuperH/ShExpressionFunctions.h Commands/CAssemblerCommand.cpp Commands/CAssemblerCommand.h Commands/CAssemblerLabel.cpp Commands/CAssemblerLabel.h Commands/CDirectiveArea.cpp Commands/CDirectiveArea.h Commands/CDirectiveConditional.cpp Commands/CDirectiveConditional.h Commands/CDirectiveData.cpp Commands/CDirectiveData.h Commands/CDirectiveFile.cpp Commands/CDirectiveFile.h Commands/CDirectiveMessage.cpp Commands/CDirectiveMessage.h Commands/CommandSequence.cpp Commands/CommandSequence.h Core/ELF/ElfTypes.h Core/ELF/ElfRelocator.cpp Core/ELF/ElfRelocator.h Core/ELF/ElfFile.cpp Core/ELF/ElfFile.h Core/Allocations.cpp Core/Allocations.h Core/Assembler.cpp Core/Assembler.h Core/Common.cpp Core/Common.h Core/Expression.cpp Core/Expression.h Core/ExpressionFunctionHandler.cpp Core/ExpressionFunctionHandler.h Core/ExpressionFunctions.cpp Core/ExpressionFunctions.h Core/FileManager.cpp Core/FileManager.h Core/Misc.cpp Core/Misc.h Core/SymbolData.cpp Core/SymbolData.h Core/SymbolTable.cpp Core/SymbolTable.h Core/Types.cpp Core/Types.h Parser/DirectivesParser.cpp Parser/DirectivesParser.h Parser/ExpressionParser.cpp Parser/ExpressionParser.h Parser/Parser.cpp Parser/Parser.h Parser/Tokenizer.cpp Parser/Tokenizer.h Util/ByteArray.cpp Util/ByteArray.h Util/CRC.cpp Util/CRC.h Util/EncodingTable.cpp Util/EncodingTable.h Util/FileClasses.cpp Util/FileClasses.h Util/FileSystem.cpp Util/FileSystem.h Util/Util.cpp Util/Util.h ) if (ARMIPS_PRECOMPILE_HEADERS) target_precompile_headers(armips PRIVATE [["Util/FileSystem.h"]] ) set_source_files_properties(Util/FileSystem.cpp PROPERTIES SKIP_PRECOMPILE_HEADERS ON) # Clang has an annoying bug when using precompiled headers where it outputs a reference to wmemchr when # __builtin_wmemchr is used. wmemchr is an inline function, which usually gets optimized away. The only # workaround seems to be to ensure that something generates a standalone wmemchr function... in other words, # referencing it and preventing it to be optimized away. See also: https://bugs.llvm.org/show_bug.cgi?id=41226 if (CLANG AND MSVC) set(CLANG_WMEMCHR_PATH ${CMAKE_CURRENT_BINARY_DIR}/clang_wmemchr.cpp) file(GENERATE OUTPUT ${CLANG_WMEMCHR_PATH} CONTENT "#include \nvoid armips_wmemchr_dummy() { wmemchr(L\"\", 0, 0); }") set_source_files_properties(${CLANG_WMEMCHR_PATH} PROPERTIES GENERATED TRUE SKIP_PRECOMPILE_HEADERS ON COMPILE_FLAGS "-Xclang -fno-inline-functions") target_sources(armips PRIVATE ${CLANG_WMEMCHR_PATH}) endif() endif() if(NOT ARMIPS_LIBRARY_ONLY) # armips-bin add_executable(armips-bin "") init_target(armips-bin) set_target_properties(armips-bin PROPERTIES OUTPUT_NAME armips) target_link_libraries(armips-bin PRIVATE armips) armips_target_sources(armips-bin PRIVATE Main/CommandLineInterface.cpp Main/CommandLineInterface.h Main/main.cpp Main/Tests.cpp Main/Tests.h ) # tests add_executable(armipstests "") init_target(armipstests) target_compile_definitions(armipstests PUBLIC ARMIPS_TESTS) target_link_libraries(armipstests PRIVATE armips) armips_target_sources(armipstests PRIVATE Main/CommandLineInterface.cpp Main/CommandLineInterface.h Main/main.cpp Main/Tests.cpp Main/Tests.h ) enable_testing() add_test(NAME armipstests COMMAND armipstests ${CMAKE_CURRENT_SOURCE_DIR}/Tests) # install install(TARGETS armips-bin RUNTIME DESTINATION .) install(FILES Readme.md DESTINATION .) endif()