diff --git a/README.md b/README.md index 9acfe59..96956b8 100644 --- a/README.md +++ b/README.md @@ -3,14 +3,23 @@ cmake-d ======= -CMake for D2 +CMake for D2 *improved* Usage ----- -1. Download and extract https://github.com/dcarp/cmake-d/archive/master.zip to a local directory \ +1. Download and extract https://github.com/dcarp/cmake-d/archive/master.zip to a local directory \ (you can use a git submodule if you want) 2. Create a D CMake Project: project(project-name D) 3. Run cmake as usual specifing the cmake-d path. To cache it, don't forget to specify the *:PATH* variable type.
``` cmake -DCMAKE_MODULE_PATH:PATH=/cmake-d ``` + +*Tip: you can add before declaring the project `set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake-d/cmake-d)` (the path to the folder with all cmake files) in order to use the normal CMake command.* + +Known issues +------------ + +This project is just a set of CMake files. It cannot do as much as a CMake binary patch. By example, regeneration of file acording a dependency file is hard coded in the Makefile backend; so when you edit a file and rebuild with this backend, it will build only the file you edited, leading to some deeper issues. + +*Workaround:* use Ninja backend. diff --git a/cmake-d/CMakeDInformation.cmake b/cmake-d/CMakeDInformation.cmake index 8e5fa3a..d1aef18 100644 --- a/cmake-d/CMakeDInformation.cmake +++ b/cmake-d/CMakeDInformation.cmake @@ -58,7 +58,7 @@ endif() # if no high specificity file was included, then try a more general one if(NOT _INCLUDED_FILE) - include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_BASE_NAME} + include(Platform/${CMAKE_SYSTEM_NAME}-${CMAKE_D_COMPILER_ID} OPTIONAL RESULT_VARIABLE _INCLUDED_FILE) endif() @@ -260,6 +260,7 @@ set(CMAKE_D_ARCHIVE_CREATE " cr ") set(CMAKE_D_ARCHIVE_APPEND " r ") set(CMAKE_D_ARCHIVE_FINISH " ") + # compile a D file into an object file if(NOT CMAKE_D_COMPILE_OBJECT) if(CMAKE_VERSION VERSION_LESS 3.4.0) @@ -284,3 +285,19 @@ mark_as_advanced( CMAKE_D_FLAGS_RELWITHDEBINFO) set(CMAKE_D_INFORMATION_LOADED 1) + +function(target_compile_versions target) + cmake_parse_arguments(CMAKE_D_COMPILE_VERSIONS "" "" "PUBLIC;PRIVATE;INTERFACE" ${ARGN}) + list(TRANSFORM CMAKE_D_COMPILE_VERSIONS_PUBLIC PREPEND "${CMAKE_D_VERSION_FLAG}") + list(TRANSFORM CMAKE_D_COMPILE_VERSIONS_PRIVATE PREPEND "${CMAKE_D_VERSION_FLAG}") + list(TRANSFORM CMAKE_D_COMPILE_VERSIONS_INTERFACE PREPEND "${CMAKE_D_VERSION_FLAG}") + if (CMAKE_D_COMPILE_VERSIONS_PUBLIC) + target_compile_options(${target} PUBLIC "$<$:${CMAKE_D_COMPILE_VERSIONS_PUBLIC}>") + endif() + if (CMAKE_D_COMPILE_VERSIONS_PRIVATE) + target_compile_options(${target} PRIVATE "$<$:${CMAKE_D_COMPILE_VERSIONS_PRIVATE}>") + endif() + if (CMAKE_D_COMPILE_VERSIONS_INTERFACE) + target_compile_options(${target} INTERFACE "$<$:${CMAKE_D_COMPILE_VERSIONS_INTERFACE}>") + endif() +endfunction() diff --git a/cmake-d/CMakeLists.txt b/cmake-d/CMakeLists.txt index e8301a1..33e8afc 100644 --- a/cmake-d/CMakeLists.txt +++ b/cmake-d/CMakeLists.txt @@ -9,7 +9,7 @@ # # See LICENSE for details. # -cmake_minimum_required(VERSION 2.8.1) +cmake_minimum_required(VERSION 3.20) project(cmake-d NONE) set(MOD_SRCS @@ -21,7 +21,7 @@ set(MOD_SRCS CMakeDetermineDCompiler.cmake FindGDCPath.cmake UseDDoc.cmake - UseDDeps.cmake + UseDDepsMakeWIP.cmake UseDub.cmake dependencies.cmake UseDUnittest.cmake diff --git a/cmake-d/Platform/Darwin-dmd.cmake b/cmake-d/Platform/Darwin-DigitalMars.cmake similarity index 93% rename from cmake-d/Platform/Darwin-dmd.cmake rename to cmake-d/Platform/Darwin-DigitalMars.cmake index 6894491..628238f 100644 --- a/cmake-d/Platform/Darwin-dmd.cmake +++ b/cmake-d/Platform/Darwin-DigitalMars.cmake @@ -27,7 +27,7 @@ set(CMAKE_BASE_NAME dmd) set(CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS "-lib") set(CMAKE_SHARED_LIBRARY_D_FLAGS "") # -pic -set(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared -defaultlib=libphobos2.so") # -shared +set(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared") # -shared set(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS "") # +s, flag for exe link to use shared lib set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG "") # -rpath set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP "") # : or empty @@ -65,3 +65,6 @@ set(CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g -L-export_dynamic ${DDOC_FLAGS}") # set(CMAKE_D_CREATE_PREPROCESSED_SOURCE " -E > ") set(CMAKE_D_CREATE_ASSEMBLY_SOURCE " -S -of") # set(CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ") +set(CMAKE_D_VERSION_FLAG "-version=") +set(CMAKE_DEPFILE_FLAGS_D "-makedeps=") +set(CMAKE_LINKER_FLAG_PREFIX "-L=") diff --git a/cmake-d/Platform/Darwin-ldc2.cmake b/cmake-d/Platform/Darwin-LDC.cmake similarity index 92% rename from cmake-d/Platform/Darwin-ldc2.cmake rename to cmake-d/Platform/Darwin-LDC.cmake index 4d17aa9..0ce37a0 100644 --- a/cmake-d/Platform/Darwin-ldc2.cmake +++ b/cmake-d/Platform/Darwin-LDC.cmake @@ -54,10 +54,13 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a") set(CMAKE_D_FLAGS_INIT "") # DMD can only produce 32-bit binaries for now set(CMAKE_D_LINK_FLAGS "") -set(CMAKE_D_FLAGS_DEBUG_INIT "-g -d-debug -L-export_dynamic ${DDOC_FLAGS}") +set(CMAKE_D_FLAGS_DEBUG_INIT "-g --d-debug -L-export_dynamic ${DDOC_FLAGS}") set(CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}") set(CMAKE_D_FLAGS_RELEASE_INIT "-O -release ${DDOC_FLAGS}") set(CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g -L-export_dynamic ${DDOC_FLAGS}") # set(CMAKE_D_CREATE_PREPROCESSED_SOURCE " -E > ") set(CMAKE_D_CREATE_ASSEMBLY_SOURCE " -S -of") # set(CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ") +set(CMAKE_D_VERSION_FLAG "--d-version=") +set(CMAKE_DEPFILE_FLAGS_D "-makedeps=") +set(CMAKE_LINKER_FLAG_PREFIX "-L=") diff --git a/cmake-d/Platform/Linux-dmd.cmake b/cmake-d/Platform/Linux-DigitalMars.cmake similarity index 93% rename from cmake-d/Platform/Linux-dmd.cmake rename to cmake-d/Platform/Linux-DigitalMars.cmake index 1cf610c..4421ee1 100644 --- a/cmake-d/Platform/Linux-dmd.cmake +++ b/cmake-d/Platform/Linux-DigitalMars.cmake @@ -27,7 +27,7 @@ set(CMAKE_BASE_NAME dmd) set(CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS "-lib") set(CMAKE_SHARED_LIBRARY_D_FLAGS "") # -pic -set(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared -defaultlib=libphobos2.so") # -shared +set(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared") # -shared set(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS "") # +s, flag for exe link to use shared lib set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG "") # -rpath set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP "") # : or empty @@ -65,3 +65,6 @@ set(CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g -L--export-dynamic ${DDOC_FLAGS}") # set(CMAKE_D_CREATE_PREPROCESSED_SOURCE " -E > ") set(CMAKE_D_CREATE_ASSEMBLY_SOURCE " -S -of") # set(CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ") +set(CMAKE_D_VERSION_FLAG "-version=") +set(CMAKE_DEPFILE_FLAGS_D "-makedeps=") +set(CMAKE_LINKER_FLAG_PREFIX "-L=") diff --git a/cmake-d/Platform/Linux-gdc.cmake b/cmake-d/Platform/Linux-GNU.cmake similarity index 54% rename from cmake-d/Platform/Linux-gdc.cmake rename to cmake-d/Platform/Linux-GNU.cmake index 0f31c26..8cd48bf 100644 --- a/cmake-d/Platform/Linux-gdc.cmake +++ b/cmake-d/Platform/Linux-GNU.cmake @@ -12,6 +12,7 @@ # See http://www.cmake.org/HTML/Copyright.html for details # +set(CMAKE_D_OUTPUT_EXTENSION .o) set(CMAKE_D_DASH_O "-o") set(CMAKE_BASE_NAME gdc) @@ -28,8 +29,27 @@ if(CMAKE_D_BUILD_DOCS) endforeach() endif() +set(CMAKE_SHARED_LIBRARY_D_FLAGS "-fPIC") # -pic +set(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared") # -shared +set(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS "") # +s, flag for exe link to use shared lib +set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG "") # -rpath +set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP "") # : or empty +set(CMAKE_INCLUDE_FLAG_D "-I") # -I +set(CMAKE_INCLUDE_FLAG_D_SEP "") # , or empty +set(CMAKE_LIBRARY_PATH_FLAG "-L") +set(CMAKE_LIBRARY_PATH_TERMINATOR "") # for the Digital Mars D compiler the link paths have to be terminated with a "/" +set(CMAKE_LINK_LIBRARY_FLAG "-l") + +set(CMAKE_LINK_LIBRARY_SUFFIX "") +set(CMAKE_STATIC_LIBRARY_PREFIX "lib") +set(CMAKE_STATIC_LIBRARY_SUFFIX ".a") +set(CMAKE_SHARED_LIBRARY_PREFIX "lib") # lib +set(CMAKE_SHARED_LIBRARY_SUFFIX ".so") # .so +set(CMAKE_EXECUTABLE_SUFFIX "") # .exe +set(CMAKE_DL_LIBS "dl") + # SET(CMAKE_D_FLAGS_INIT "-fversion=Posix -fversion=${CMAKE_BUILD_TYPE}Build ${DSTDLIB_FLAGS}") -set(CMAKE_D_FLAGS_INIT "") +set(CMAKE_D_FLAGS_INIT "-fall-instantiations ") set(CMAKE_D_FLAGS_DEBUG_INIT "-g ${DDOC_FLAGS}") set(CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}") set(CMAKE_D_FLAGS_RELEASE_INIT "-O3 -fomit-frame-pointer -fweb -frelease -finline-functions ${DDOC_FLAGS}") @@ -37,5 +57,8 @@ set(CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O2 -g ${DDOC_FLAGS}") # set(CMAKE_D_CREATE_PREPROCESSED_SOURCE " -E > ") set(CMAKE_D_CREATE_ASSEMBLY_SOURCE " -S -o ") # set(CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ") +set(CMAKE_LINKER_FLAG_PREFIX "-Wl,") set(CMAKE_INCLUDE_FLAG_D "-I") # -I +set(CMAKE_D_VERSION_FLAG "-fversion=") +set(CMAKE_DEPFILE_FLAGS_D "-MD -MT -MF ") diff --git a/cmake-d/Platform/Linux-ldc2.cmake b/cmake-d/Platform/Linux-LDC.cmake similarity index 88% rename from cmake-d/Platform/Linux-ldc2.cmake rename to cmake-d/Platform/Linux-LDC.cmake index 7b06a80..20437ba 100644 --- a/cmake-d/Platform/Linux-ldc2.cmake +++ b/cmake-d/Platform/Linux-LDC.cmake @@ -27,7 +27,7 @@ set(CMAKE_BASE_NAME ldc2) set(CMAKE_STATIC_LIBRARY_CREATE_D_FLAGS "-lib") set(CMAKE_SHARED_LIBRARY_D_FLAGS "") # -pic -set(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared") # -shared +set(CMAKE_SHARED_LIBRARY_CREATE_D_FLAGS "-shared -link-defaultlib-shared=false") # -shared set(CMAKE_SHARED_LIBRARY_LINK_D_FLAGS "") # +s, flag for exe link to use shared lib set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG "") # -rpath set(CMAKE_SHARED_LIBRARY_RUNTIME_D_FLAG_SEP "") # : or empty @@ -54,10 +54,13 @@ set(CMAKE_FIND_LIBRARY_SUFFIXES ".so" ".a") set(CMAKE_D_FLAGS_INIT "") # DMD can only produce 32-bit binaries for now set(CMAKE_D_LINK_FLAGS "") -set(CMAKE_D_FLAGS_DEBUG_INIT "-g -d-debug -L--export-dynamic ${DDOC_FLAGS}") +set(CMAKE_D_FLAGS_DEBUG_INIT "-g --d-debug -L--export-dynamic ${DDOC_FLAGS}") set(CMAKE_D_FLAGS_MINSIZEREL_INIT "-Os ${DDOC_FLAGS}") set(CMAKE_D_FLAGS_RELEASE_INIT "-O -release ${DDOC_FLAGS}") set(CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g -L--export-dynamic ${DDOC_FLAGS}") # set(CMAKE_D_CREATE_PREPROCESSED_SOURCE " -E > ") set(CMAKE_D_CREATE_ASSEMBLY_SOURCE " -S -of") # set(CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ") +set(CMAKE_D_VERSION_FLAG "--d-version=") +set(CMAKE_DEPFILE_FLAGS_D "-makedeps=") +set(CMAKE_LINKER_FLAG_PREFIX "-L=") diff --git a/cmake-d/Platform/Windows-dmd.cmake b/cmake-d/Platform/Windows-DigitalMars.cmake similarity index 91% rename from cmake-d/Platform/Windows-dmd.cmake rename to cmake-d/Platform/Windows-DigitalMars.cmake index def1fd3..5943a90 100644 --- a/cmake-d/Platform/Windows-dmd.cmake +++ b/cmake-d/Platform/Windows-DigitalMars.cmake @@ -54,3 +54,6 @@ set(CMAKE_D_FLAGS_DEBUG_INIT "-g -debug ${DDOC_FLAGS}") set(CMAKE_D_FLAGS_RELEASE_INIT "-O -release -inline ${DDOC_FLAGS}") set(CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O -g ${DDOC_FLAGS}") set(CMAKE_D_CREATE_ASSEMBLY_SOURCE " -S -of") +set(CMAKE_D_VERSION_FLAG "-version=") +set(CMAKE_DEPFILE_FLAGS_D "-makedeps=") +set(CMAKE_LINKER_FLAG_PREFIX "-L=") diff --git a/cmake-d/Platform/Windows-gdc.cmake b/cmake-d/Platform/Windows-GNU.cmake similarity index 87% rename from cmake-d/Platform/Windows-gdc.cmake rename to cmake-d/Platform/Windows-GNU.cmake index a476fe3..ecfa438 100644 --- a/cmake-d/Platform/Windows-gdc.cmake +++ b/cmake-d/Platform/Windows-GNU.cmake @@ -33,3 +33,6 @@ set(CMAKE_D_FLAGS_RELWITHDEBINFO_INIT "-O2 -g ${DDOC_FLAGS}") # set(CMAKE_D_CREATE_PREPROCESSED_SOURCE " -E > ") set(CMAKE_D_CREATE_ASSEMBLY_SOURCE " -S -o ") # set(CMAKE_INCLUDE_SYSTEM_FLAG_D "-isystem ") +set(CMAKE_D_VERSION_FLAG "-fversion=") +set(CMAKE_DEPFILE_FLAGS_D "-MD -MT -MF ") +set(CMAKE_LINKER_FLAG_PREFIX "-Wl,") diff --git a/cmake-d/UseDDeps.cmake b/cmake-d/UseDDeps.cmake deleted file mode 100644 index 41284f5..0000000 --- a/cmake-d/UseDDeps.cmake +++ /dev/null @@ -1,63 +0,0 @@ -# Dependency tracking for D -# -# Copyright (c) 2010 Jens Mueller -# -# All rights reserved. -# -# See LICENSE for details. -# - -macro(add_executable_with_dependencies _target) - # extract D source files from arguments - foreach(file ${ARGV}) - if(${file} MATCHES "\\.d$") - list(APPEND d_source_files ${file}) - endif() - endforeach() - - #message("D files in arguments: ${d_source_files}") - - foreach(file IN LISTS d_source_files) - set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}") - set(dependency_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${file}-depend.cmake") - set(dependency_files ${dependency_files} ${dependency_file}) - - #message("Checking dependencies for ${source_file}") - #message("Put into ${dependency_file}") - # TODO - # better way to get the included directories - get_directory_property(include_dirs INCLUDE_DIRECTORIES) - set(INCLUDES ) - foreach(include_dir IN LISTS include_dirs) - list(APPEND INCLUDES "${CMAKE_INCLUDE_FLAG_D}${include_dir}") - endforeach() - - execute_process( - COMMAND ${CMAKE_COMMAND} - -D "CMAKE_D_COMPILER:STRING=${CMAKE_D_COMPILER}" - -D "CMAKE_D_FLAGS:STRING=${CMAKE_D_FLAGS}" - -D "include_directories:STRING=${INCLUDES}" - -D "source_file:STRING=${source_file}" - -D "dependency_file:STRING=${dependency_file}" - -P "${CMAKE_ROOT}/Modules/dependencies.cmake" # TODO hard coded path - ) - - # load dependencies from file - include(${dependency_file}) - #message("DEPENDENCIES ${D_DMD_DEPEND}") - - add_custom_command( - OUTPUT ${dependency_file} - DEPENDS ${D_DMD_DEPEND} - COMMAND ${CMAKE_COMMAND} - -D "CMAKE_D_COMPILER:STRING=${CMAKE_D_COMPILER}" - -D "CMAKE_D_FLAGS:STRING=${CMAKE_D_FLAGS}" - -D "include_directories:STRING=${INCLUDES}" - -D "source_file:STRING=${source_file}" - -D "dependency_file:STRING=${dependency_file}" - -P "${CMAKE_ROOT}/Modules/dependencies.cmake" # TODO hard coded path - COMMENT "Scanning for dependencies") - endforeach() - - add_executable(${ARGV} ${dependency_files}) -endmacro() diff --git a/cmake-d/UseDDepsMakeWIP.cmake b/cmake-d/UseDDepsMakeWIP.cmake new file mode 100644 index 0000000..9146ad3 --- /dev/null +++ b/cmake-d/UseDDepsMakeWIP.cmake @@ -0,0 +1,48 @@ +set(cmake_d_dir ${CMAKE_CURRENT_LIST_DIR}) + +function(depfile_from_file depfile file) + file(RELATIVE_PATH file "${CMAKE_CURRENT_SOURCE_DIR}" "${full_file}") + set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}") + set(deps_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/UseDDeps/") + set(${depfile} "${deps_dir}${file}.dep" PARENT_SCOPE) +endfunction() + +function(resolve_dependencies target) + get_target_property(d_source_files ${target} SOURCES) + + # extract D source files from arguments + #message("D files in arguments: ${d_source_files}") + + foreach(full_file IN LISTS d_source_files) + set(CMAKE_DEPENDS_USE_COMPILER true) + depfile_from_file(dependency_file ${full_file}) + message("${dependency_file}") + + string(REPLACE "" "${dependency_file}" depflag "${CMAKE_DEPFILE_FLAGS_D}") +# add_custom_command(DEPFILE "${dependency_file}" OUTPUT "${dependency_file}" DEPENDS "") +# set_source_files_properties("${full_file}" PROPERTIES OBJECT_DEPENDS "${dependency_file}") + endforeach() +endfunction() + + +macro(add_executable_with_dependencies _target) + # extract D source files from arguments + foreach(file ${ARGV}) + if(${file} MATCHES "\\.d$") + list(APPEND d_source_files ${file}) + endif() + endforeach() + + #message("D files in arguments: ${d_source_files}") + + foreach(file IN LISTS d_source_files) + file(RELATIVE_PATH file "${CMAKE_CURRENT_SOURCE_DIR}" "${full_file}") + set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}") + set(deps_dir "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/UseDDeps/") + set(dependency_file "${deps_dir}${file}.dep") + get_filename_component(deps_source_dir "${dependency_file}" DIRECTORY) + set("${CMAKE_D_COMPILER} -o- -M") + endforeach() + + add_executable(${ARGV} ${dependency_files}) +endmacro() diff --git a/cmake-d/UseDub.cmake b/cmake-d/UseDub.cmake index fa9b226..1c70aa5 100644 --- a/cmake-d/UseDub.cmake +++ b/cmake-d/UseDub.cmake @@ -20,7 +20,14 @@ endif() set(DUB_REGISTRY "https://code.dlang.org/packages") file(MAKE_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp) -if(NOT CMAKE_D_COMPILER) +if (CMAKE_CROSSCOMPILING) + # todo: change this + set(CMAKE_D_COMPILER_NATIVE gdc) +else() + set(CMAKE_D_COMPILER_NATIVE ${CMAKE_D_COMPILER}) +endif() + +if(NOT CMAKE_D_COMPILER_NATIVE) message(FATAL_ERROR "UseDub needs a D compiler or use it in a D project.") endif() @@ -33,22 +40,33 @@ if(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubUrl) PATHS ${CMAKE_ROOT}/Modules ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH PATH_SUFFIXES "UseDub") get_filename_component(SEMVER_PATH ${SEMVER_SRC} PATH) - execute_process(COMMAND ${CMAKE_D_COMPILER} -I${SEMVER_PATH} ${DUB_GET_PACKAGE_URL_D_SRC} ${SEMVER_SRC} - WORKING_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp) + execute_process(COMMAND ${CMAKE_D_COMPILER_NATIVE} -I${SEMVER_PATH} ${DUB_GET_PACKAGE_URL_D_SRC} ${SEMVER_SRC} + ${CMAKE_D_DASH_O}DubUrl WORKING_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp) unset(DUB_GET_PACKAGE_URL_D_SRC CACHE) endif() if(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubToCMake) find_file(DUB_PACKAGE_TO_CMAKE_D_SRC "DubToCMake.d" PATHS ${CMAKE_ROOT}/Modules ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH PATH_SUFFIXES "UseDub") - execute_process(COMMAND ${CMAKE_D_COMPILER} ${DUB_PACKAGE_TO_CMAKE_D_SRC} + execute_process(COMMAND ${CMAKE_D_COMPILER_NATIVE} ${DUB_PACKAGE_TO_CMAKE_D_SRC} ${CMAKE_D_DASH_O}DubToCMake WORKING_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp) unset(DUB_PACKAGE_TO_CMAKE_D_SRC CACHE) endif() -include(ExternalProject) +include(FetchContent) + +function(DubProject_Add name_full) + string(FIND "${name_full}" ":" subpackage) + + if(subpackage EQUAL -1) + set(name "${name_full}") + else() + string(REPLACE ":" ";" name_split ${name_full}) + + list(GET name_split 0 name) + list(GET name_split 1 subpackage) + endif() -function(DubProject_Add name) if(NOT EXISTS ${DUB_DIRECTORY}/${name}.json) file(DOWNLOAD ${DUB_REGISTRY}/${name}.json ${DUB_DIRECTORY}/${name}.json STATUS status) list(GET status 0 statusCode) @@ -60,7 +78,7 @@ function(DubProject_Add name) endif() if(${ARGC} GREATER 1) - execute_process(COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubUrl -p ${name}.json -r ${DUB_REGISTRY} -t ${ARGN} + execute_process(COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubUrl -p ${name}.json -r ${DUB_REGISTRY} -t ${ARGV1} WORKING_DIRECTORY ${DUB_DIRECTORY}) else() execute_process(COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubUrl -p ${name}.json -r ${DUB_REGISTRY} @@ -69,16 +87,19 @@ function(DubProject_Add name) include(${DUB_DIRECTORY}/${name}.cmake) - ExternalProject_Add(${name} - DOWNLOAD_DIR ${DUB_DIRECTORY}/archive/${name} - SOURCE_DIR ${DUB_DIRECTORY}/source/${name} - URL ${DUB_PACKAGE_URL} - PATCH_COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubToCMake -p package.json - INSTALL_DIR ${DUB_DIRECTORY}/export - CMAKE_CACHE_ARGS - -DCMAKE_MODULE_PATH:PATH=${CMAKE_MODULE_PATH} - -DCMAKE_INSTALL_PREFIX:PATH= - -DDUB_DIRECTORY:PATH=${DUB_DIRECTORY}) + if(${ARGC} GREATER 2) + FetchContent_Declare( + ${name}_proj + URL ${DUB_PACKAGE_URL} + PATCH_COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubToCMake -c ${ARGV2} -s ${name_full} -p ${name} + ) + else() + FetchContent_Declare( + ${name}_proj + URL ${DUB_PACKAGE_URL} + PATCH_COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubToCMake -s ${name_full} -p ${name} + ) + endif() + FetchContent_MakeAvailable(${name}_proj) - include_directories(${DUB_DIRECTORY}/source/${name}/source ${DUB_DIRECTORY}/source/${name}/src) endfunction() diff --git a/cmake-d/UseDub/DubToCMake.d b/cmake-d/UseDub/DubToCMake.d index 9c9a204..fbea2e3 100644 --- a/cmake-d/UseDub/DubToCMake.d +++ b/cmake-d/UseDub/DubToCMake.d @@ -1,87 +1,165 @@ import std.algorithm; +import std.algorithm.searching; +import std.array; import std.file; import std.getopt; import std.json; +import std.path; +import std.process; import std.stdio; import std.string; -import std.process; + +string cmakeFile = "CMakeLists.txt"; +string configuration = ""; +string packageName = ""; +string subPackage = ""; + +string[] processedTargets = []; + +string[] configurationArg; int main(string[] args) { - string cmakeFile = "CMakeLists.txt"; - string dubFile = ""; - getopt(args, - "package|p", &dubFile, + "package|p", &packageName, + "configuration|c", &configuration, + "subpackage|s", &subPackage, "output|o", &cmakeFile); - if (dubFile != "") - { - stderr.writeln("-p is deprecated and does not have any effect anymore. Please keep the default package file name."); + if (!configuration.empty) + configurationArg = ["-c", configuration]; + else { + configurationArg = []; } - string json = execute(["dub", "describe"]).output; - JSONValue dubRoot = parseJSON(json); - JSONValue root = dubRoot["packages"][0]; - string target = root["targetName"].str; + if (subPackage.canFind(':')) { + subPackage = ":" ~ subPackage.split(':')[1]; + } else { + subPackage = ""; + } - string cmake = q"< -cmake_minimum_required(VERSION 2.8) + auto packageArgs = [subPackage]; -project(%1$s D) + if (subPackage.canFind(",")) { + packageArgs = subPackage[1..$].split(',').map!((s) => ":" ~ s).array; + } -find_file(APP_MAIN_FILE - NAMES app.d main.d %1$s/main.d %1$s/app.d - PATHS source src NO_DEFAULT_PATH) + auto cmake = appender!string(); -file(GLOB_RECURSE SRC_FILES source/*.d src/*.d) -if(APP_MAIN_FILE) - list(REMOVE_ITEM SRC_FILES ${APP_MAIN_FILE}) -endif() + cmake ~= format!q"< +# Header +cmake_minimum_required(VERSION 3.18) + +project(%s D) + +>"(packageName ~ "_proj"); + + foreach (pkg; packageArgs) { + auto packageArg = pkg; + + auto p = pipeProcess(["dub", "describe"] ~ configurationArg ~ packageArg, Redirect.stdout); + + auto apd = appender!string(); + foreach (line; p.stdout.byLine) + { + apd ~= line.idup; + } + + string json = apd[]; + auto dubRoot = parseJSON(json); + JSONValue root = dubRoot["packages"][0]; + + cmake ~= includePackage(dubRoot, root); + } -include_directories(source src) ->".format(root["name"].str); + + std.file.write(cmakeFile, cmake[]); + + return 0; +} + +string includePackage(JSONValue dubRoot, JSONValue root) { + string target = root["targetName"].str.replace(":", "::"); + string[] tmp = root["name"].str.split(":"); + string subTarget = ""; + if (tmp.length > 1) + subTarget = tmp[1]; + + if (processedTargets.canFind(target)) + return ""; + + string cmake = format!"# Section: %s\n"(target); + bool isInterface = false; + + string normalizedPath(string path) { + return cast(string) asNormalizedPath(root["path"].str.asRelativePath(getcwd).array ~ "/" ~ path).array; + } + + cmake ~= format!"set(SRC_FILES %-(%s %))"( + root["files"].array.map!( + (val) { + if (val["role"].str == "source" || val["role"].str == "import_") { + string path = normalizedPath(val["path"].str); + return exists(path) ? path : ""; + } + else + return ""; + }).filter!(a => a != "").array + ); switch ("targetType" in root.object ? root["targetType"].str : "autodetect") { case "autodetect": - cmake ~= q"< + cmake ~= q"< +find_file(APP_MAIN_FILE + NAMES app.d main.d %1$s/main.d %1$s/app.d + PATHS source src NO_DEFAULT_PATH) + +set(SRC_FILES %2$-(%s %)) if(APP_MAIN_FILE) + list(REMOVE_ITEM SRC_FILES ${APP_MAIN_FILE}) add_executable(%1$s ${SRC_FILES} ${APP_MAIN_FILE}) else() add_library(%1$s ${SRC_FILES}) endif() >".format(target); - break; + break; case "none": - break; + cmake ~= q"< +add_library(%s INTERFACE ${SRC_FILES}) +>".format(target); + isInterface = true; + break; case "executable": - cmake ~= q"< + cmake ~= q"< add_executable(%s ${SRC_FILES} ${APP_MAIN_FILE}) >".format(target); - break; + break; case "library": - cmake ~= q"< + cmake ~= q"< add_library(%s ${SRC_FILES}) >".format(target); - break; + break; case "sourceLibrary": - break; case "staticLibrary": - cmake ~= q"< + cmake ~= q"< add_library(%s STATIC ${SRC_FILES}) >".format(target); - break; + break; case "dynamicLibrary": - cmake ~= q"< + cmake ~= q"< add_library(%s SHARED ${SRC_FILES}) >".format(target); - break; + break; default: - assert(false, "Unknown targetType"); - break; + assert(false, "Unknown targetType"); + break; } + cmake ~= q"< +target_include_directories(%s %s %-(%s %)) +>".format(target, isInterface ? "INTERFACE" : "PUBLIC", root["importPaths"].array.map!((val) => normalizedPath(val.str)).array ~ (subTarget.empty ? [] : [subTarget])); + cmake ~= q"< install(TARGETS %s RUNTIME DESTINATION bin @@ -94,13 +172,55 @@ install(TARGETS %s cmake ~= "\ninclude(UseDub)\n"; foreach (dependency; root["dependencies"].array) { - string version_ = "~" ~ dubRoot["packages"].array.find!((obj) => obj["name"] == dependency)[0]["version"].str; - cmake ~= "DubProject_Add(%s %s)\n".format(dependency, version_); + if (dependency.str.startsWith(dubRoot["rootPackage"].str.split(":")[0])) { + auto p = pipeProcess(["dub", "describe", dependency.str], Redirect.stdout); + + auto apd = appender!string(); + foreach (line; p.stdout.byLine) + { + apd ~= line.idup; + } + + auto newDubRoot = parseJSON(apd[]); + auto pkg = newDubRoot["packages"].array.find!((obj) => obj["name"] == dependency)[0]; + + cmake = includePackage(newDubRoot, pkg) ~ cmake; + } else { + auto pkg = dubRoot["packages"].array.find!((obj) => obj["name"] == dependency)[0]; + string version_ = pkg["version"].str; + string configuration = pkg["configuration"].str; + cmake ~= "DubProject_Add(%s %s %s)\n".format(dependency.str, version_, configuration); + } } - cmake ~= "\nadd_dependencies(%s %-(%s %))\n".format(target, root["dependencies"].array); + + cmake ~= ("\ntarget_link_libraries(%s " ~ (isInterface ? "INTERFACE" : "PUBLIC") ~ " %-(%s %))\n").format(target, root["dependencies"].array.map!((val) => val.str.replace(":", "::"))); } - std.file.write(cmakeFile, cmake); + if ("versions" in root.object && root["versions"].array.length > 0) { + cmake ~= format!q"< +target_compile_versions(%s PUBLIC %-(%s %)) +>"(target, root["versions"].array.map!(a => a.str)); + } - return 0; + if ("libs" in root.object && root["libs"].array.length > 0) { + cmake ~= format!q"< +target_link_libraries(%s PUBLIC %-(%s %)) +>"(target, root["libs"].array.map!(a => `"` ~ a.str ~ `"`)); + } + + if ("lflags" in root.object && root["lflags"].array.length > 0) { + cmake ~= format!q"< +target_link_options(%s PUBLIC "%-(${CMAKE_LINKER_FLAG_PREFIX}%s %)") +>"(target, root["lflags"].array.map!(a => a.str)); + } + + if (target != root["name"].str) + cmake ~= format!q"< +add_library(%s ALIAS %s) +>"(root["name"].str.replace(":", "::"), target); + + processedTargets ~= target; + cmake ~= format!"# End section %s \n"(target); + + return cmake; } diff --git a/cmake-d/UseDub/DubUrl.d b/cmake-d/UseDub/DubUrl.d index 691b861..26a2656 100644 --- a/cmake-d/UseDub/DubUrl.d +++ b/cmake-d/UseDub/DubUrl.d @@ -50,6 +50,7 @@ int main(string[] args) string registryUrl = "https://code.dlang.org/packages"; string registryFile = ""; string packageVersion = ""; + string configuration = ""; bool listVersions; string outputPath = ".";