From 1a2bef3ec8dedfb14c292b74839df510a041bebf Mon Sep 17 00:00:00 2001 From: Dragos Carp Date: Sun, 9 Mar 2014 14:06:50 +0100 Subject: [PATCH] Added dub support --- cmake-d/CMakeLists.txt | 1 + cmake-d/UseDub.cmake | 65 ++++++++++++++++++++++++++ cmake-d/UseDub/DubToCMake.d | 93 +++++++++++++++++++++++++++++++++++++ cmake-d/UseDub/DubUrl.d | 91 ++++++++++++++++++++++++++++++++++++ tests/dub/CMakeLists.txt | 7 +++ 5 files changed, 257 insertions(+) create mode 100644 cmake-d/UseDub.cmake create mode 100644 cmake-d/UseDub/DubToCMake.d create mode 100644 cmake-d/UseDub/DubUrl.d create mode 100644 tests/dub/CMakeLists.txt diff --git a/cmake-d/CMakeLists.txt b/cmake-d/CMakeLists.txt index d66d895..1ffd2ec 100644 --- a/cmake-d/CMakeLists.txt +++ b/cmake-d/CMakeLists.txt @@ -22,6 +22,7 @@ SET (MOD_SRCS FindGDCPath.cmake UseDDoc.cmake UseDDeps.cmake + UseDUB.cmake dependencies.cmake UseDUnittest.cmake FindPhobos.cmake diff --git a/cmake-d/UseDub.cmake b/cmake-d/UseDub.cmake new file mode 100644 index 0000000..aa085bf --- /dev/null +++ b/cmake-d/UseDub.cmake @@ -0,0 +1,65 @@ +# This modules add functions for downloading and building dub dependencies. +# This code sets the following variables and functions: +# +# DUB_DIRECTORY = the full path to Dub pacakges +# +# DubProject_Add( [version]) +# +#============================================================================ +# Copyright (c) 2014 Dragos Carp +# +# All rights reserved. +# +# See LICENSE for details. +# + +set(DUB_DIRECTORY ${CMAKE_BINARY_DIR}/UseDub CACHE PATH "Dub packages direcotry") + +set(DUB_REGISTRY "http://code.dlang.org/packages") +file(MAKE_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp) + +if(NOT CMAKE_D_COMPILER) + message(FATAL_ERROR "UseDub needs a D compiler or use it in a D project.") +endif(NOT CMAKE_D_COMPILER) + +#compile json parsers +if(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubUrl OR 1) + find_file(DUB_GET_PACKAGE_URL_D_SRC "DubUrl.d" + PATHS ${CMAKE_ROOT}/Modules ${CMAKE_MODULE_PATH} NO_DEFAULT_PATH + PATH_SUFFIXES "UseDub") + execute_process(COMMAND ${CMAKE_D_COMPILER} ${DUB_GET_PACKAGE_URL_D_SRC} + WORKING_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp) + unset(DUB_GET_PACKAGE_URL_D_SRC CACHE) +endif(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubUrl OR 1) +if(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubToCMake OR 1) + 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} + WORKING_DIRECTORY ${DUB_DIRECTORY}/CMakeTmp) + unset(DUB_PACKAGE_TO_CMAKE_D_SRC CACHE) +endif(NOT EXISTS ${DUB_DIRECTORY}/CMakeTmp/DubToCMake OR 1) + +include(ExternalProject) + +function(DubProject_Add name) + if(NOT EXISTS ${DUB_DIRECTORY}/${name}.json) + file(DOWNLOAD ${DUB_REGISTRY}/${name}.json ${DUB_DIRECTORY}/${name}.json) + endif(NOT EXISTS ${DUB_DIRECTORY}/${name}.json) + + if(${ARGC} GREATER 1) + execute_process(COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubUrl -p ${name}.json -t ${ARGN} + WORKING_DIRECTORY ${DUB_DIRECTORY}) + else(${ARGC} GREATER 1) + execute_process(COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubUrl -p ${name}.json + WORKING_DIRECTORY ${DUB_DIRECTORY}) + endif(${ARGC} GREATER 1) + + include(${DUB_DIRECTORY}/${name}.cmake) + + ExternalProject_Add(${name} + DOWNLOAD_DIR ${DUB_DIRECTORY}/${name} + URL ${DUB_PACKAGE_URL} + PATCH_COMMAND ${DUB_DIRECTORY}/CMakeTmp/DubToCMake -p package.json + CMAKE_CACHE_ARGS -DCMAKE_MODULE_PATH:PATH=${CMAKE_MODULE_PATH}) +endfunction() diff --git a/cmake-d/UseDub/DubToCMake.d b/cmake-d/UseDub/DubToCMake.d new file mode 100644 index 0000000..5478851 --- /dev/null +++ b/cmake-d/UseDub/DubToCMake.d @@ -0,0 +1,93 @@ +import std.file; +import std.getopt; +import std.json; +import std.stdio; +import std.string; + +int main(string[] args) +{ + string dubFile = "dub.json"; + string cmakeFile = "CMakeLists.txt"; + + getopt(args, + "package|p", &dubFile, + "output|o", &cmakeFile); + + if (!exists(dubFile)) + { + stderr.writefln("Cannot find file: '%s'", dubFile); + return -1; + } + + string json = readText(dubFile); + JSONValue root = parseJSON(json); + + string cmake = q"< +cmake_minimum_required(VERSION 2.8) + +project(%1$s D) + +find_file(APP_MAIN_FILE + NAMES app.d main.d %1$s/main.d %1$s/app.d + PATHS source src NO_DEFAULT_PATH) + +file(GLOB_RECURSE SRC_FILES source/*.d src/*.d) +if(APP_MAIN_FILE) + list(REMOVE_ITEM SRC_FILES ${APP_MAIN_FILE}) +endif(APP_MAIN_FILE) +>".format(root["name"].str); + + switch ("targetType" in root.object ? root["targetType"].str : "autodetect") + { + case "autodetect": + cmake ~= q"< +if(APP_MAIN_FILE) + add_executable(%1$s ${SRC_FILES} ${APP_MAIN_FILE}) +else(APP_MAIN_FILE) + add_library(%1$s ${SRC_FILES}) +endif(APP_MAIN_FILE) +>".format(root["targetName"].str); + break; + case "none": + break; + case "executable": + cmake ~= q"< +add_executable(%s ${SRC_FILES} ${APP_MAIN_FILE}) +>".format(root["targetName"].str); + break; + case "library": + cmake ~= q"< +add_library(%s ${SRC_FILES}) +>".format(root["targetName"].str); + break; + case "sourceLibrary": + break; + case "staticLibrary": + cmake ~= q"< +add_library(%s STATIC ${SRC_FILES}) +>".format(root["targetName"].str); + break; + case "dynamicLibrary": + cmake ~= q"< +add_library(%s SHARED ${SRC_FILES}) +>".format(root["targetName"].str); + break; + default: + assert(false, "Unknown targetType"); + break; + } + + if ("dependencies" in root.object) + { + cmake ~= "\ninclude(UseDub)\n"; + foreach (dependency, version_; root["dependencies"].object) + { + cmake ~= "DubProject_Add(%s %s)\n".format(dependency, version_.str); + } + } + + + std.file.write(cmakeFile, cmake); + + return 0; +} diff --git a/cmake-d/UseDub/DubUrl.d b/cmake-d/UseDub/DubUrl.d new file mode 100644 index 0000000..5ee55d3 --- /dev/null +++ b/cmake-d/UseDub/DubUrl.d @@ -0,0 +1,91 @@ +import std.algorithm; +import std.array; +import std.file; +import std.getopt; +import std.json; +import std.stdio; +import std.string; + +int main(string[] args) +{ + string registryFile = ""; + string packageVersion = ""; + bool listVersions; + string outputPath = "."; + + getopt(args, + "package|p", ®istryFile, + "tag|t", &packageVersion, + "list|l", &listVersions, + "output|o", &outputPath); + + if (registryFile.empty) + { + stderr.writeln("Package registry file (.json) need to be specified."); + return -1; + } + + if (!exists(registryFile) && !registryFile.endsWith(".json")) + registryFile ~= ".json"; + + if (!exists(registryFile)) + { + stderr.writefln("Package registry file '%s' not found.", registryFile); + return -1; + } + + string json = readText(registryFile); + JSONValue node; + JSONValue root = parseJSON(json); + + if (packageVersion.empty) + { + node = root["versions"][0]; + } + else + { + auto range = root["versions"].array.find!"a[\"version\"].str == b"(packageVersion); + if (!range.empty) + { + node = range[0]; + } + else + { + stderr.writefln("No version tagged '%s' found.", packageVersion); + return -1; + } + } + + if (registryFile.endsWith(".json")) + { + registryFile = registryFile[0..$-5]; + } + + if (listVersions) + { + writefln("Package '%s'", registryFile); + + foreach(n; root["versions"].array) + { + writefln(" %s => %s", n["version"].str, n["downloadUrl"].str); + } + } + + packageVersion = node["version"].str; + auto packageUrl = node["downloadUrl"].str; + auto packageName = root["name"].str; + + if (!outputPath.isDir) + { + stderr.writefln("Output path '%s' need to be a directory.", outputPath); + return -1; + } + + string output = "set(DUB_PACKAGE_NAME, \"%s\")\n".format(packageName) ~ + "set(DUB_PACKAGE_VERSION \"%s\")\n".format(packageVersion) ~ + "set(DUB_PACKAGE_URL \"%s\")\n".format(packageUrl); + + std.file.write(outputPath ~ "/" ~ packageName ~ ".cmake", output); + + return 0; +} diff --git a/tests/dub/CMakeLists.txt b/tests/dub/CMakeLists.txt new file mode 100644 index 0000000..73f742a --- /dev/null +++ b/tests/dub/CMakeLists.txt @@ -0,0 +1,7 @@ +cmake_minimum_required(VERSION 2.8) + +project(DubTest D) + +include(UseDub) + +DubProject_Add(derelict-sdl2 ~2.0.0)