Last active
April 11, 2020 07:39
-
-
Save dolinenkov/e5c7154e5f6ab1729746667a8b0b8401 to your computer and use it in GitHub Desktop.
CMake function for adding standard layout modules
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# universal function for adding a standard layout module | |
# usage: add_module({MODULE_NAME} [NO_CONSOLE] [DIR direcory] [TYPE executable|library] [DEPENDS target1 target2 ...]) | |
# NO_CONSOLE (Win32): set entry point to WinMain instead of main() | |
# TYPE: module type, default is library | |
# DIR: module base directory | |
# DEPENDS: list of libraries(another modules) to link with | |
# DEBUG_DIR: debugger startup directory (Visual Studio only) | |
function(add_module MODULE_NAME) | |
if(NOT MODULE_NAME) | |
message("add_module(): module name not specified") | |
return() | |
endif() | |
cmake_parse_arguments( | |
"ARG" | |
"NO_CONSOLE;MAKE_DEFAULT" | |
"TYPE;DIR;DEBUG_DIR" | |
"DEPENDS" | |
${ARGN}) # prefix, options, one-valued keywords, multi-valued keywords, input arguments | |
if(NOT ARG_TYPE) | |
set(ARG_TYPE "library") | |
endif() | |
# default directory | |
if(NOT ARG_DIR) | |
message("add_module(${MODULE_NAME}): DIR not specified, using " ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_NAME}) | |
set(ARG_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_NAME}) | |
endif() | |
if(NOT IS_DIRECTORY ${ARG_DIR}) | |
message("add_module(${MODULE_NAME}): module directory doesn't exist") | |
return() | |
endif() | |
set(INCLUDE_DIR ${ARG_DIR}/include) | |
set(SOURCES_DIR ${ARG_DIR}/sources) | |
# collect public headers | |
set(PUBLIC_SOURCES "") | |
foreach(LOCATION "${INCLUDE_DIR}/${MODULE_NAME}/*.h;${INCLUDE_DIR}/${MODULE_NAME}/*.hh") | |
set(_PUBLIC_SOURCES "") | |
file(GLOB_RECURSE _PUBLIC_SOURCES CONFIGURE_DEPENDS ${LOCATION}) | |
foreach(FILENAME ${_PUBLIC_SOURCES}) | |
list(APPEND PUBLIC_SOURCES ${FILENAME}) | |
endforeach() | |
endforeach() | |
# collect sources and private headers | |
set(PRIVATE_SOURCES "") | |
foreach(LOCATION "${SOURCES_DIR}/*.h;${SOURCES_DIR}/*.hh;${SOURCES_DIR}/*.c;${SOURCES_DIR}/*.cc") | |
set(_PRIVATE_SOURCES "") | |
file(GLOB_RECURSE _PRIVATE_SOURCES CONFIGURE_DEPENDS ${LOCATION}) | |
foreach(FILENAME ${_PRIVATE_SOURCES}) | |
list(APPEND PRIVATE_SOURCES ${FILENAME}) | |
endforeach() | |
endforeach() | |
# make whole source file list | |
set(ALL_SOURCES "") | |
if(PUBLIC_SOURCES) | |
set(ALL_SOURCES ${ALL_SOURCES} ${PUBLIC_SOURCES}) | |
endif() | |
if(PRIVATE_SOURCES) | |
set(ALL_SOURCES ${ALL_SOURCES} ${PRIVATE_SOURCES}) | |
endif() | |
if(NOT ALL_SOURCES) | |
message("add_module(${MODULE_NAME}): no sources found, skipping") | |
return() | |
endif() | |
# add target | |
if(ARG_TYPE STREQUAL "executable") | |
if(NO_CONSOLE) | |
set(ALL_SOURCES WIN32 ${ALL_SOURCES}) | |
endif() | |
add_executable(${MODULE_NAME} ${ALL_SOURCES}) | |
if(ARG_DEBUG_DIR) | |
if(MSVC_IDE) | |
# Visual Studio: debug launches at root directory | |
set_target_properties(${MODULE_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY ${ARG_DEBUG_DIR}) | |
else() | |
message("add_module(${MODULE_NAME}: DEBUG_DIR is not supported by current generator, ignoring") | |
endif() | |
endif() | |
elseif(ARG_TYPE STREQUAL "library") | |
add_library(${MODULE_NAME} ${ALL_SOURCES}) | |
target_include_directories(${MODULE_NAME} PUBLIC ${INCLUDE_DIR}) | |
else() | |
message("add_module(${MODULE_NAME}): unknown type: ${ARG_TYPE}, skipping") | |
return() | |
endif() | |
# Visual Studio: mark project as startup | |
if(ARG_MAKE_DEFAULT) | |
if(ARG_TYPE STREQUAL "executable") | |
set_property(DIRECTORY PROPERTY VS_STARTUP_PROJECT "${MODULE_NAME}") | |
else() | |
message("add_module(${MODULE_NAME}): only executable target can be marked as default") | |
endif() | |
endif() | |
# configure dependencies | |
if(ARG_DEPENDS) | |
set(LINK_PUBLIC_ARGS "") | |
set(LINK_INTERFACE_ARGS "") | |
set(DEPEND_ARGS "") | |
foreach(DEPENDENCY ${ARG_DEPENDS}) | |
message(${DEPENDENCY}) | |
if(TARGET ${DEPENDENCY}) | |
get_target_property(TARGET_TYPE ${DEPENDENCY} TYPE) | |
# handle linking | |
if(${TARGET_TYPE} STREQUAL "EXECUTABLE") | |
#? | |
elseif(${TARGET_TYPE} STREQUAL "INTERFACE_LIBRARY") | |
list(APPEND LINK_INTERFACE_ARGS ${DEPENDENCY}) | |
elseif(${TARGET_TYPE} STREQUAL "STATIC_LIBRARY" OR ${TARGET_TYPE} STREQUAL "SHARED_LIBRARY" OR ${TARGET_TYPE} STREQUAL "MODULE_LIBRARY") | |
list(APPEND LINK_PUBLIC_ARGS ${DEPENDENCY}) | |
endif() | |
# handle regular dependencies | |
list(APPEND DEPEND_ARGS ${DEPENDENCY}) | |
else() | |
message("add_module(${MODULE_NAME}): '${TARGET}' is not a valid target name, skipping") | |
endif() | |
endforeach() | |
# build link libraries list | |
set(LINK_ARGS "") | |
if(LINK_PUBLIC_ARGS) | |
set(LINK_ARGS PUBLIC ${LINK_PUBLIC_ARGS}) | |
endif() | |
if(LINK_INTERFACE_ARGS) | |
set(LINK_ARGS INTERFACE ${LINK_INTERFACE_ARGS}) | |
endif() | |
if(LINK_ARGS) | |
target_link_libraries(${MODULE_NAME} ${LINK_ARGS}) | |
endif() | |
# build dependency list | |
if(DEPEND_ARGS) | |
add_dependencies(${MODULE_NAME} ${DEPEND_ARGS}) | |
endif() | |
endif() | |
endfunction() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment