cmake_minimum_required(VERSION 3.0) get_filename_component(project_name ${CMAKE_CURRENT_SOURCE_DIR} NAME) project(${project_name}) set(EXTENSION "cpp") set(CMAKE_C_STANDARD 99) set(CMAKE_CXX_STANDARD 14) set(GEN_BINARY OFF) set(GEN_LIBRARY OFF) set(LIB_TYPE STATIC) # NONE, STATIC, SHARED, MODULE set(LIBS_TYPE STATIC) set(FLAGS_ANY "-Wall -Wextra -fopenmp -Winline -Wfatal-errors") set(FLAGS_DEBUG "-DDEBUG -Og -g -fsanitize=thread") set(FLAGS_RELEASE "-DNDEBUG -O2") set(SRCDIRS src) set(LIBSDIRS libsrc) set(TESTSDIRS tests) set(EXAMPLESDIRS examples benchmarks) set(MANDIR man) set(INCLUDE_DIRS inc) set(LIBRARIES "") set(USER_LIBRARIES "") set(CMAKE_EXPORT_COMPILE_COMMANDS ON) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${FLAGS_ANY}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${FLAGS_ANY} ${FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${FLAGS_ANY} ${FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${FLAGS_ANY}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAGS_ANY} ${FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${FLAGS_ANY} ${FLAGS_RELEASE}") if(USE_SANITIZER STREQUAL "Address") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=address") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") elseif(USE_SANITIZER STREQUAL "Leak") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=leak") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=leak") elseif(USE_SANITIZER STREQUAL "Thread") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread") elseif(USE_SANITIZER STREQUAL "Undefined") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=undefined") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=undefined") endif() ## Libraries if(NOT ${LIB_TYPE} MATCHES "^NONE$") # Project library if(GEN_LIBRARY) set(lib_src "") foreach(srcdir ${SRCDIRS}) set(srcpath ${CMAKE_CURRENT_SOURCE_DIR}/${srcdir}) file(GLOB_RECURSE tmpsrc ${srcpath}/*.${EXTENSION}) list(APPEND lib_src ${tmpsrc}) endforeach() set(lib ${PROJECT_NAME}) if(lib_src) message(STATUS "+ Library: ${lib}") add_library(${lib} ${LIB_TYPE} ${lib_src}) target_include_directories(${lib} PUBLIC ${INCLUDE_DIRS}) target_link_libraries(${lib} ${LIBRARIES}) list(APPEND USER_LIBRARIES ${lib}) else() message(WARNING "! Library ${lib}: no sources") endif() endif() endif() ## Other libraries if(NOT ${LIBS_TYPE} MATCHES "^NONE$") foreach(libsdir ${LIBSDIRS}) set(libspath ${CMAKE_CURRENT_SOURCE_DIR}/${libsdir}) file(GLOB libs RELATIVE ${libspath} ${libspath}/*) if(libs) foreach(child ${libs}) set(lib "") if(IS_DIRECTORY ${libspath}/${child}) set(lib ${child}) file(GLOB_RECURSE lib_src ${libspath}/${child}/*.${EXTENSION}) else() message(WARNING "! Ignoring file: ${libsdir}/${child}") endif() if(lib) if(lib_src) message(STATUS "+ Library: ${lib}") add_library(${lib} ${LIBS_TYPE} ${lib_src}) target_include_directories(${lib} PUBLIC ${INCLUDE_DIRS}) target_link_libraries(${lib} ${LIBRARIES}) list(APPEND USER_LIBRARIES ${lib}) else() message(WARNING "! Library ${lib}: no sources") endif() endif() endforeach() endif() endforeach() endif() ## Binary if(GEN_BINARY) set(src "") foreach(srcdir ${SRCDIRS}) set(srcpath ${CMAKE_CURRENT_SOURCE_DIR}/${srcdir}) file(GLOB_RECURSE tmpsrc ${srcpath}/*.${EXTENSION}) list(APPEND src ${tmpsrc}) endforeach() set(bin ${PROJECT_NAME}) if(src) if(GEN_LIBRARY) set(bin ${bin}.bin) endif() message(STATUS "+ Binary: ${bin}") add_executable(${bin} ${src}) target_include_directories(${bin} PUBLIC ${LIBSDIRS} ${INCLUDE_DIRS}) target_link_libraries(${bin} ${LIBRARIES} ${USER_LIBRARIES}) else() message(WARNING "! Binary ${bin}: no sources") endif() endif() ## Tests foreach(testsdir ${TESTSDIRS}) set(testspath ${CMAKE_CURRENT_SOURCE_DIR}/${testsdir}) file(GLOB_RECURSE tests_src ${testspath}/*.${EXTENSION}) if(tests_src) set(tests ${testsdir}_${PROJECT_NAME}) message(STATUS "+ Tests: ${tests}") add_executable(${tests} ${tests_src}) target_include_directories(${tests} PUBLIC ${SRCDIRS} ${LIBSDIRS} ${INCLUDE_DIRS}) target_link_libraries(${tests} ${LIBRARIES} ${USER_LIBRARIES}) endif() endforeach() ## Examples foreach(examplesdir ${EXAMPLESDIRS}) set(examplespath ${CMAKE_CURRENT_SOURCE_DIR}/${examplesdir}) file(GLOB examples RELATIVE ${examplespath} ${examplespath}/*) if(examples) foreach(child ${examples}) set(example_bin_filename "") set(example "") if(IS_DIRECTORY ${examplespath}/${child}) set(example_bin_filename ${child}) set(example ${examplesdir}_${example_bin_filename}) file(GLOB_RECURSE example_src ${examplespath}/${child}/*.${EXTENSION}) else() get_filename_component(extension ${child} EXT) if(${extension} MATCHES "^.${EXTENSION}$") get_filename_component(example_name ${child} NAME_WE) set(example_bin_filename ${example_name}) set(example ${examplesdir}_${example_bin_filename}) set(example_src ${examplespath}/${child}) endif() endif() if(example) if(example_src) message(STATUS "+ Example: ${examplesdir}/${example}") add_executable(${example} ${example_src}) target_include_directories(${example} PUBLIC ${SRCDIRS} ${LIBSDIRS} ${INCLUDE_DIRS}) target_link_libraries(${example} ${LIBRARIES} ${USER_LIBRARIES}) set_target_properties(${example} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/${examplesdir}) set_target_properties(${example} PROPERTIES OUTPUT_NAME ${example_bin_filename}) else() message(WARNING "! Example ${example}: no sources") endif() endif() endforeach() endif() endforeach() ## Man pages set(MANPATH ${CMAKE_CURRENT_SOURCE_DIR}/${MANDIR}) set(MAN_OUTPATH ${CMAKE_BINARY_DIR}/deb/usr/share/man) file(GLOB_RECURSE man_src RELATIVE ${MANPATH} ${MANPATH}/*) if(man_src) set(man_outfiles "") foreach(man_file IN LISTS man_src) set(man_outfile ${MAN_OUTPATH}/${man_file}.gz) get_filename_component(man_outdir ${man_outfile} DIRECTORY) list(APPEND man_outfiles ${man_outfile}) message(STATUS "+ manpage: ${man_file}") add_custom_command(OUTPUT ${man_outfile} COMMAND ${CMAKE_COMMAND} -E make_directory ${man_outdir} COMMAND ${CMAKE_COMMAND} -E copy ${MANPATH}/${man_file} ${MAN_OUTPATH}/${man_file} COMMAND gzip -f ${MAN_OUTPATH}/${man_file} DEPENDS ${MANPATH}/${man_file}) endforeach() add_custom_target(man ALL DEPENDS ${man_outfiles}) endif()