diff --git a/.clang-format b/.clang-format index f833c75..37c1b1a 100644 --- a/.clang-format +++ b/.clang-format @@ -42,7 +42,7 @@ BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakStringLiterals: true -ColumnLimit: 100 +ColumnLimit: 150 CommentPragmas: '^ IWYU pragma:' CompactNamespaces: false ConstructorInitializerAllOnOneLineOrOnePerLine: false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a723513..13a9079 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -2,18 +2,23 @@ name: CMake on: [push, pull_request] -env: - # Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.) - BUILD_TYPE: Release - jobs: build: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: - os: [windows-latest, macos-10.15, ubuntu-18.04] - + os: [windows-2016, windows-2019, macos-10.15, ubuntu-16.04, ubuntu-18.04, ubuntu-20.04] + env: + BUILD_TYPE: Release steps: - - uses: actions/checkout@v2 + - name: Checkout + uses: actions/checkout@v2 - name: Build - run: cmake -S. -Bbin -DCMAKE_BUILD_TYPE=$BUILD_TYPE && cmake --build bin --parallel --config $BUILD_TYPE + run: | + cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} + cmake --build build --config ${{ env.BUILD_TYPE }} --parallel + - name: Test + run: | + cd build/tests + ctest -C ${{ env.BUILD_TYPE }} diff --git a/.gitignore b/.gitignore index 2c4432e..65fe6fa 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,7 @@ compile_commands.json temp.* .vs .cache -build*/ \ No newline at end of file +build*/ +.idea/ +cmake-build*/ +CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt index 17108a7..8eb3abc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,87 +1,125 @@ # This file was generated automatically by cmkr. -# Regenerate CMakeLists.txt file when necessary -include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT) +cmake_minimum_required(VERSION 2.8...3.8) -if(CMKR_INCLUDE_RESULT) - cmkr() -endif() - -cmake_minimum_required(VERSION 3.15) - -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - -project(cmkr - VERSION 0.1.4 - LANGUAGES C CXX - DESCRIPTION "CMakeLists generator from TOML" - ) - -include(FetchContent) - -FetchContent_Declare( - filesystem - GIT_REPOSITORY https://github.com/gulrak/filesystem - GIT_SHALLOW ON - ) +# Regenerate CMakeLists.txt automatically in the root project +set(CMKR_ROOT_PROJECT OFF) +if(CMAKE_CURRENT_SOURCE_DIR STREQUAL CMAKE_SOURCE_DIR) + set(CMKR_ROOT_PROJECT ON) -FetchContent_MakeAvailable(filesystem) + # Bootstrap cmkr + include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT) + if(CMKR_INCLUDE_RESULT) + cmkr() + endif() -FetchContent_Declare( - mpark_variant - URL https://github.com/mpark/variant/archive/v1.4.0.tar.gz - ) + # Enable folder support + set_property(GLOBAL PROPERTY USE_FOLDERS ON) +endif() -FetchContent_MakeAvailable(mpark_variant) +# Create a configure-time dependency on cmake.toml to improve IDE support +if(CMKR_ROOT_PROJECT) + configure_file(cmake.toml cmake.toml COPYONLY) +endif() -FetchContent_Declare( - toml11 - GIT_REPOSITORY https://github.com/ToruNiina/toml11 - GIT_SHALLOW ON - ) +# Hack to hide a warning during cmkr bootstrapping on Windows +if(CMAKE_BUILD_TYPE) +endif() -FetchContent_MakeAvailable(toml11) -set(CMKRLIB_SOURCES - src/cmake.cpp - src/gen.cpp - src/help.cpp - src/build.cpp - src/error.cpp - ) +project(cmkr + LANGUAGES + CXX + VERSION + 0.1.3 + DESCRIPTION + "CMakeLists generator from TOML" +) + +# third_party +set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER}) +if(CMAKE_FOLDER) + set(CMAKE_FOLDER "${CMAKE_FOLDER}/third_party") +else() + set(CMAKE_FOLDER third_party) +endif() +add_subdirectory(third_party) +set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) + +# tests +set(CMKR_CMAKE_FOLDER ${CMAKE_FOLDER}) +if(CMAKE_FOLDER) + set(CMAKE_FOLDER "${CMAKE_FOLDER}/tests") +else() + set(CMAKE_FOLDER tests) +endif() +add_subdirectory(tests) +set(CMAKE_FOLDER ${CMKR_CMAKE_FOLDER}) + + +# Target cmkrlib +set(cmkrlib_SOURCES + "src/cmkrlib/args.cpp" + "src/cmkrlib/build.cpp" + "src/cmkrlib/cmake.cpp" + "src/cmkrlib/error.cpp" + "src/cmkrlib/gen.cpp" + "src/cmkrlib/help.cpp" + "src/cmkrlib/cmake.hpp" + "src/cmkrlib/enum_helper.hpp" + "src/cmkrlib/fs.hpp" + "include/args.h" + "include/build.h" + "include/error.h" + "include/gen.h" + "include/help.h" + "include/literals.h" + cmake.toml +) + +add_library(cmkrlib STATIC ${cmkrlib_SOURCES}) + +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkrlib_SOURCES}) -add_library(cmkrlib STATIC ${CMKRLIB_SOURCES}) +target_compile_features(cmkrlib PUBLIC + cxx_std_11 +) target_include_directories(cmkrlib PUBLIC include - ) +) target_link_libraries(cmkrlib PUBLIC - toml11::toml11 + toml11 ghc_filesystem mpark_variant - ) + ordered_map +) -target_compile_features(cmkrlib PUBLIC - cxx_std_11 - ) +# Target cmkr +set(cmkr_SOURCES + "src/main.cpp" + cmake.toml +) + +add_executable(cmkr ${cmkr_SOURCES}) -set(CMKR_SOURCES - src/main.cpp - src/args.cpp - ) +get_directory_property(CMKR_VS_STARTUP_PROJECT DIRECTORY ${PROJECT_SOURCE_DIR} DEFINITION VS_STARTUP_PROJECT) +if(NOT CMKR_VS_STARTUP_PROJECT) + set_property(DIRECTORY ${PROJECT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT cmkr) +endif() -add_executable(cmkr ${CMKR_SOURCES}) +source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${cmkr_SOURCES}) -target_link_libraries(cmkr PUBLIC +target_link_libraries(cmkr PRIVATE cmkrlib - ) +) install( - TARGETS cmkr - DESTINATION ${CMAKE_INSTALL_PREFIX}/bin - COMPONENT cmkr - ) - - - + TARGETS + cmkr + DESTINATION + "${CMAKE_INSTALL_PREFIX}/bin" + COMPONENT + cmkr +) diff --git a/README.md b/README.md index 492aa19..169068e 100644 --- a/README.md +++ b/README.md @@ -22,9 +22,9 @@ minimum = "3.15" name = "app" version = "0.1.0" -[[bin]] +[[target]] name = "app" -type = "exe" +type = "executable" sources = ["src/main.cpp"] ``` @@ -43,19 +43,19 @@ toml11 = { git = "https://github.com/ToruNiina/toml11" } filesystem = { git = "https://github.com/gulrak/filesystem" } mpark_variant = { url = "https://github.com/mpark/variant/archive/v1.4.0.tar.gz" } -[[bin]] +[[target]] name = "cmkrlib" type = "static" sources = ["src/cmake.cpp", "src/gen.cpp", "src/help.cpp", "src/build.cpp", "src/error.cpp"] -include-dirs = ["include"] -features = ["cxx_std_11"] -link-libs = ["toml11::toml11", "ghc_filesystem"] +include-directories = ["include"] +compile-features = ["cxx_std_11"] +link-libraries = ["toml11::toml11", "ghc_filesystem"] -[[bin]] +[[target]] name = "cmkr" -type = "exe" +type = "executable" sources = ["src/main.cpp", "src/args.cpp"] -link-libs = ["cmkrlib"] +link-libraries = ["cmkrlib"] [[install]] targets = ["cmkr"] @@ -68,7 +68,7 @@ Currently supported fields: minimum = "3.15" # required description = "" # optional subdirs = [] # optional -bin-dir = "bin" # optional +build-dir = "build" # optional cpp-flags = [] # optional c-flags = [] # optional link-flags = [] # optional @@ -97,15 +97,15 @@ toml11 = { git = "https://github.com/ToruNiina/toml11", tag = "v3.5.0" } # optio APP_BUILD_STUFF = false # optional APP_OTHER_STUFF = { comment = "does other stuff", value = false } # optional -[[bin]] # required, can define several binaries +[[target]] # required, can define several binaries name = "app" # required -type = "exe" # required (exe || lib || shared || static || interface) +type = "executable" # required (executable || library || shared || static || interface) sources = ["src/*.cpp"] # required, supports globbing -include-dirs = ["include"] # optional +include-directories = ["include"] # optional alias = "" # optional -features = [] # optional -definitions = [] # optional -link-libs = [] # optional +compile-features = [] # optional +compile-definitions = [] # optional +link-libraries = [] # optional properties = { PROPERTY1 = "property1", ... } # optional [[test]] # optional, can define several @@ -125,13 +125,13 @@ The cmkr executable can be run from the command-line: ``` Usage: cmkr [arguments] arguments: - init [exe|lib|shared|static|interface] Starts a new project in the same directory. - gen Generates CMakeLists.txt file. - build Run cmake and build. - install Run cmake --install. Needs admin privileges. - clean Clean the build directory. - help Show help. - version Current cmkr version. + init [executable|library|shared|static|interface] Starts a new project in the same directory. + gen Generates CMakeLists.txt file. + build Run cmake and build. + install Run cmake --install. Needs admin privileges. + clean Clean the build directory. + help Show help. + version Current cmkr version. ``` The build command invokes cmake and the default build-system on your platform (unless a generator is specified), it also accepts extra cmake build arguments: ``` @@ -140,20 +140,20 @@ cmkr build --config Release ## Binary types -### exe -Executable binary. +### executable +Executable binary. Equivalent to [add_executable(name)](https://cmake.org/cmake/help/latest/command/add_executable.html). -### lib -Library, can be static or shared depending on the BUILD_SHARED_LIBS variable. +### library +Library, can be static or shared depending on the BUILD_SHARED_LIBS variable. Equivalent to [add_library()](https://cmake.org/cmake/help/latest/command/add_library.html). ### static -Static library/archive. +Static library/archive. Equivalent to [add_library(name STATIC)](https://cmake.org/cmake/help/latest/command/add_library.html). ### shared -Shared/dynamic library. +Shared/dynamic library. Equivalent to [add_library(name SHARED)](https://cmake.org/cmake/help/latest/command/add_library.html). ### interface -Header-only library. +Header-only library. Equivalent to [add_library(name INTERFACE)](https://cmake.org/cmake/help/latest/command/add_library.html). ## Roadmap - Support more cmake fields. diff --git a/cmake.toml b/cmake.toml index d0b6437..8e2775d 100644 --- a/cmake.toml +++ b/cmake.toml @@ -1,29 +1,29 @@ [cmake] -minimum = "3.15" -description = "CMakeLists generator from TOML" +version = "2.8...3.8" [project] +cmake-before = """ +# Hack to hide a warning during cmkr bootstrapping on Windows +if(CMAKE_BUILD_TYPE) +endif() +""" name = "cmkr" version = "0.1.4" +description = "CMakeLists generator from TOML" +languages = ["CXX"] +subdirs = ["third_party", "tests"] -[fetch-content] -toml11 = { git = "https://github.com/ToruNiina/toml11" } -filesystem = { git = "https://github.com/gulrak/filesystem" } -mpark_variant = { url = "https://github.com/mpark/variant/archive/v1.4.0.tar.gz" } - -[[bin]] -name = "cmkrlib" +[target.cmkrlib] type = "static" -sources = ["src/cmake.cpp", "src/gen.cpp", "src/help.cpp", "src/build.cpp", "src/error.cpp"] -include-dirs = ["include"] -features = ["cxx_std_11"] -link-libs = ["toml11::toml11", "ghc_filesystem", "mpark_variant"] +sources = ["src/cmkrlib/*.cpp", "src/cmkrlib/*.hpp", "include/*.h"] +include-directories = ["include"] +compile-features = ["cxx_std_11"] +link-libraries = ["toml11", "ghc_filesystem", "mpark_variant", "ordered_map"] -[[bin]] -name = "cmkr" -type = "exe" -sources = ["src/main.cpp", "src/args.cpp"] -link-libs = ["cmkrlib"] +[target.cmkr] +type = "executable" +sources = ["src/main.cpp"] +link-libraries = ["cmkrlib"] [[install]] targets = ["cmkr"] diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 68219a3..c35b2dd 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -1,24 +1,27 @@ -# This file was generated automatically by cmkr. - -# Regenerate CMakeLists.txt file when necessary -include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT) - -if(CMKR_INCLUDE_RESULT) - cmkr() -endif() - -cmake_minimum_required(VERSION 3.15) - -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) - -set(example_PROJECT_VERSION 0.1.0) -project(example VERSION ${example_PROJECT_VERSION}) - -set(EXAMPLE_SOURCES - src/example.cpp - ) - -add_executable(example ${EXAMPLE_SOURCES}) - - - +# This file was generated automatically by cmkr. + +# Regenerate CMakeLists.txt file when necessary +include(cmkr.cmake OPTIONAL RESULT_VARIABLE CMKR_INCLUDE_RESULT) + +if(CMKR_INCLUDE_RESULT) + cmkr() +endif() + +cmake_minimum_required(VERSION 3.15) + +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +set(example_PROJECT_VERSION 0.1.0) +project(example VERSION ${example_PROJECT_VERSION}) + +set(EXAMPLE_SOURCES + src/example.cpp + cmake.toml +) + +add_executable(example ${EXAMPLE_SOURCES}) + +source_group(TREE ${PROJECT_SOURCE_DIR} FILES ${EXAMPLE_SOURCES}) + + + diff --git a/cmake/cmake.toml b/cmake/cmake.toml index b8089b3..267e481 100644 --- a/cmake/cmake.toml +++ b/cmake/cmake.toml @@ -7,7 +7,7 @@ minimum = "3.15" name = "example" version = "0.1.0" -[[bin]] +[[target]] name = "example" -type = "exe" +type = "executable" sources = ["src/example.cpp"] \ No newline at end of file diff --git a/cmake/cmkr.cmake b/cmake/cmkr.cmake index be50bd3..325f766 100644 --- a/cmake/cmkr.cmake +++ b/cmake/cmkr.cmake @@ -1,23 +1,41 @@ include_guard() +# Change these defaults to point to your infrastructure if desired +set(CMKR_REPO "https://github.com/MoAlyousef/cmkr" CACHE STRING "cmkr git repository") +set(CMKR_TAG "archive_84f6b39f" CACHE STRING "cmkr git tag (this needs to be available forever)") +set(CMKR_EXECUTABLE "" CACHE FILEPATH "cmkr executable") +set(CMKR_SKIP_GENERATION OFF CACHE BOOL "skip automatic cmkr generation") + +# Disable cmkr if generation is disabled +if(CMKR_SKIP_GENERATION) + message(STATUS "[cmkr] Skipping automatic cmkr generation") + macro(cmkr) + endmacro() + return() +endif() + # Disable cmkr if no cmake.toml file is found -if(NOT EXISTS ${CMAKE_CURRENT_LIST_DIR}/cmake.toml) - message(STATUS "[cmkr] Not found: ${CMAKE_CURRENT_LIST_DIR}/cmake.toml") +if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml") + message(AUTHOR_WARNING "[cmkr] Not found: ${CMAKE_CURRENT_SOURCE_DIR}/cmake.toml") macro(cmkr) endmacro() return() endif() -# Add a build-time dependency on the contents of cmake.toml to regenerate the CMakeLists.txt when modified -configure_file(${CMAKE_CURRENT_LIST_DIR}/cmake.toml ${CMAKE_CURRENT_BINARY_DIR}/cmake.toml COPYONLY) +# Convert a Windows native path to CMake path +if(CMKR_EXECUTABLE MATCHES "\\\\") + string(REPLACE "\\" "/" CMKR_EXECUTABLE_CMAKE "${CMKR_EXECUTABLE}") + set(CMKR_EXECUTABLE "${CMKR_EXECUTABLE_CMAKE}" CACHE FILEPATH "" FORCE) + unset(CMKR_EXECUTABLE_CMAKE) +endif() # Helper macro to execute a process (COMMAND_ERROR_IS_FATAL ANY is 3.19 and higher) -macro(cmkr_exec) +function(cmkr_exec) execute_process(COMMAND ${ARGV} RESULT_VARIABLE CMKR_EXEC_RESULT) if(NOT CMKR_EXEC_RESULT EQUAL 0) message(FATAL_ERROR "cmkr_exec(${ARGV}) failed (exit code ${CMKR_EXEC_RESULT})") endif() -endmacro() +endfunction() # Windows-specific hack (CMAKE_EXECUTABLE_PREFIX is not set at the moment) if(WIN32) @@ -27,86 +45,103 @@ else() endif() # Use cached cmkr if found -if(DEFINED CACHE{CMKR_EXECUTABLE} AND EXISTS ${CMKR_EXECUTABLE}) +set(CMKR_CACHED_EXECUTABLE "${CMAKE_CURRENT_BINARY_DIR}/_cmkr/bin/${CMKR_EXECUTABLE_NAME}") +if(CMKR_EXECUTABLE AND EXISTS "${CMKR_EXECUTABLE}") message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'") +elseif(CMKR_EXECUTABLE AND NOT CMKR_EXECUTABLE STREQUAL CMKR_CACHED_EXECUTABLE) + message(FATAL_ERROR "[cmkr] '${CMKR_EXECUTABLE}' not found") else() - if(DEFINED CACHE{CMKR_EXECUTABLE}) - message(VERBOSE "[cmkr] '${CMKR_EXECUTABLE}' not found") + set(CMKR_EXECUTABLE "${CMKR_CACHED_EXECUTABLE}" CACHE FILEPATH "Full path to cmkr executable" FORCE) + message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'") + + message(STATUS "[cmkr] Fetching cmkr...") + set(CMKR_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/_cmkr") + if(EXISTS "${CMKR_DIRECTORY}") + cmkr_exec("${CMAKE_COMMAND}" -E rm -rf "${CMKR_DIRECTORY}") endif() - set(CMKR_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/_cmkr) - set(CMKR_EXECUTABLE ${CMAKE_CURRENT_BINARY_DIR}/_cmkr/bin/${CMKR_EXECUTABLE_NAME} CACHE INTERNAL "Full path to cmkr executable") + find_package(Git QUIET REQUIRED) + cmkr_exec("${GIT_EXECUTABLE}" + clone + --config advice.detachedHead=false + --branch ${CMKR_TAG} + --depth 1 + ${CMKR_REPO} + "${CMKR_DIRECTORY}" + ) + message(STATUS "[cmkr] Building cmkr...") + cmkr_exec("${CMAKE_COMMAND}" + "${CMKR_DIRECTORY}" + "-B${CMKR_DIRECTORY}/build" + "-DCMAKE_BUILD_TYPE=Release" + "-DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}" + ) + cmkr_exec("${CMAKE_COMMAND}" + --build "${CMKR_DIRECTORY}/build" + --config Release + --parallel + ) + cmkr_exec("${CMAKE_COMMAND}" + --install "${CMKR_DIRECTORY}/build" + --config Release + --prefix "${CMKR_DIRECTORY}" + --component cmkr + ) if(NOT EXISTS ${CMKR_EXECUTABLE}) - message(VERBOSE "[cmkr] Bootstrapping '${CMKR_EXECUTABLE}'") - message(STATUS "[cmkr] Fetching cmkr...") - if(EXISTS ${CMKR_DIRECTORY}) - cmkr_exec(${CMAKE_COMMAND} -E rm -rf ${CMKR_DIRECTORY}) - endif() - find_package(Git QUIET REQUIRED) - set(CMKR_REPO "https://github.com/moalyousef/cmkr") - cmkr_exec(${GIT_EXECUTABLE} clone ${CMKR_REPO} ${CMKR_DIRECTORY}) - cmkr_exec(${CMAKE_COMMAND} ${CMKR_DIRECTORY} -B${CMKR_DIRECTORY}/build -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${CMKR_DIRECTORY}) - cmkr_exec(${CMAKE_COMMAND} --build ${CMKR_DIRECTORY}/build --parallel --config Release) - cmkr_exec(${CMAKE_COMMAND} --install ${CMKR_DIRECTORY}/build --config Release --prefix ${CMKR_DIRECTORY} --component cmkr) - if(NOT EXISTS ${CMKR_EXECUTABLE}) - message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'") - endif() - cmkr_exec(${CMKR_EXECUTABLE} version OUTPUT_VARIABLE CMKR_VERSION) - string(STRIP ${CMKR_VERSION} CMKR_VERSION) - message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}") - else() - message(VERBOSE "[cmkr] Found cmkr: '${CMKR_EXECUTABLE}'") + message(FATAL_ERROR "[cmkr] Failed to bootstrap '${CMKR_EXECUTABLE}'") endif() + cmkr_exec("${CMKR_EXECUTABLE}" version) + message(STATUS "[cmkr] Bootstrapped ${CMKR_EXECUTABLE}") endif() -execute_process(COMMAND ${CMKR_EXECUTABLE} version - OUTPUT_VARIABLE CMKR_VERSION +execute_process(COMMAND "${CMKR_EXECUTABLE}" version RESULT_VARIABLE CMKR_EXEC_RESULT ) if(NOT CMKR_EXEC_RESULT EQUAL 0) - unset(CMKR_EXECUTABLE CACHE) message(FATAL_ERROR "[cmkr] Failed to get version, try clearing the cache and rebuilding") endif() -string(STRIP ${CMKR_VERSION} CMKR_VERSION) -message(STATUS "[cmkr] Using ${CMKR_VERSION}") # This is the macro that contains black magic macro(cmkr) # When this macro is called from the generated file, fake some internal CMake variables - get_source_file_property(CMKR_CURRENT_LIST_FILE ${CMAKE_CURRENT_LIST_FILE} CMKR_CURRENT_LIST_FILE) + get_source_file_property(CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" CMKR_CURRENT_LIST_FILE) if(CMKR_CURRENT_LIST_FILE) - set(CMAKE_CURRENT_LIST_FILE ${CMKR_CURRENT_LIST_FILE}) - get_filename_component(CMAKE_CURRENT_LIST_DIR ${CMAKE_CURRENT_LIST_FILE} DIRECTORY) + set(CMAKE_CURRENT_LIST_FILE "${CMKR_CURRENT_LIST_FILE}") + get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" DIRECTORY) endif() # File-based include guard (include_guard is not documented to work) - get_source_file_property(CMKR_INCLUDE_GUARD ${CMAKE_CURRENT_LIST_FILE} CMKR_INCLUDE_GUARD) + get_source_file_property(CMKR_INCLUDE_GUARD "${CMAKE_CURRENT_LIST_FILE}" CMKR_INCLUDE_GUARD) if(NOT CMKR_INCLUDE_GUARD) - set_source_files_properties(${CMAKE_CURRENT_LIST_FILE} PROPERTIES CMKR_INCLUDE_GUARD TRUE) + set_source_files_properties("${CMAKE_CURRENT_LIST_FILE}" PROPERTIES CMKR_INCLUDE_GUARD TRUE) + + file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_PRE) # Generate CMakeLists.txt - cmkr_exec(${CMKR_EXECUTABLE} gen -y - WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} - OUTPUT_VARIABLE CMKR_GEN_OUTPUT + cmkr_exec("${CMKR_EXECUTABLE}" gen + WORKING_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" ) - string(STRIP ${CMKR_GEN_OUTPUT} CMKR_GEN_OUTPUT) - message(STATUS "[cmkr] ${CMKR_GEN_OUTPUT}") - # Copy the now-generated CMakeLists.txt to CMakerLists.txt - # This is done because you cannot include() a file you are currently in - set(CMKR_TEMP_FILE ${CMAKE_CURRENT_LIST_DIR}/CMakerLists.txt) - configure_file(CMakeLists.txt ${CMKR_TEMP_FILE} COPYONLY) - - # Add the macro required for the hack at the start of the cmkr macro - set_source_files_properties(${CMKR_TEMP_FILE} PROPERTIES - CMKR_CURRENT_LIST_FILE ${CMAKE_CURRENT_LIST_FILE} - ) - - # 'Execute' the newly-generated CMakeLists.txt - include(${CMKR_TEMP_FILE}) - - # Delete the generated file - file(REMOVE ${CMKR_TEMP_FILE}) - - # Do not execute the rest of the original CMakeLists.txt - return() + file(SHA256 "${CMAKE_CURRENT_LIST_FILE}" CMKR_LIST_FILE_SHA256_POST) + + if(NOT CMKR_LIST_FILE_SHA256_PRE STREQUAL CMKR_LIST_FILE_SHA256_POST) + # Copy the now-generated CMakeLists.txt to CMakerLists.txt + # This is done because you cannot include() a file you are currently in + set(CMKR_TEMP_FILE "${CMAKE_CURRENT_SOURCE_DIR}/CMakerLists.txt") + configure_file(CMakeLists.txt "${CMKR_TEMP_FILE}" COPYONLY) + + # Add the macro required for the hack at the start of the cmkr macro + set_source_files_properties("${CMKR_TEMP_FILE}" PROPERTIES + CMKR_CURRENT_LIST_FILE "${CMAKE_CURRENT_LIST_FILE}" + ) + + # 'Execute' the newly-generated CMakeLists.txt + include("${CMKR_TEMP_FILE}") + + # Delete the generated file + file(REMOVE "${CMKR_TEMP_FILE}") + + # Do not execute the rest of the original CMakeLists.txt + return() + endif() + # Resume executing the unmodified CMakeLists.txt endif() endmacro() diff --git a/include/gen.h b/include/gen.h index 0e808af..a2c99c0 100644 --- a/include/gen.h +++ b/include/gen.h @@ -6,7 +6,7 @@ namespace gen { int generate_project(const char *typ); -int generate_cmake(const char *path); +int generate_cmake(const char *path, bool root = true); } // namespace gen } // namespace cmkr diff --git a/include/literals.h b/include/literals.h index 1ef6bae..accaf34 100644 --- a/include/literals.h +++ b/include/literals.h @@ -1,20 +1,19 @@ #pragma once -const char *hello_world = R"lit( +static const char *hello_world = &R"lit( #include int %s() { std::cout << "Hello World!\n"; return 0; } +)lit"[1]; // skip initial newline -)lit"; - -const char *cmake_toml = R"lit( +static const char *cmake_toml = &R"lit( [cmake] -minimum = "3.15" +version = "3.15" # subdirs = [] -# bin-dir = "" +# build-dir = "" # cpp-flags = [] # c-flags = [] # link-flags = [] @@ -31,18 +30,17 @@ version = "0.1.0" # [options] -[[bin]] +[[target]] name = "%s" type = "%s" sources = ["src/*.cpp"] -include-dirs = ["include"] +include-directories = ["include"] # alias = "" -# features = [] -# definitions = [] -# link-libs = [] +# compile-features = [] +# compile-definitions = [] +# link-libraries = [] [[install]] %s = ["%s"] destination = "${CMAKE_INSTALL_PREFIX}/%s" - -)lit"; +)lit"[1]; // skip initial newline diff --git a/src/cmake.cpp b/src/cmake.cpp deleted file mode 100644 index f84305d..0000000 --- a/src/cmake.cpp +++ /dev/null @@ -1,242 +0,0 @@ -#include "cmake.hpp" - -#include "fs.hpp" -#include -#include - -namespace cmkr { -namespace cmake { - -namespace detail { -std::vector to_string_vec( - const std::vector> - &vals) { - std::vector temp; - for (const auto &val : vals) - temp.push_back(val.as_string()); - return temp; -} -} // namespace detail - -CMake::CMake(const std::string &path, bool build) { - if (!fs::exists(fs::path(path) / "cmake.toml")) { - throw std::runtime_error("[cmkr] error: No cmake.toml was found!"); - } - const auto toml = toml::parse((fs::path(path) / "cmake.toml").string()); - if (build) { - if (toml.contains("cmake")) { - const auto &cmake = toml::find(toml, "cmake"); - - if (cmake.contains("bin-dir")) { - bin_dir = toml::find(cmake, "bin-dir").as_string(); - } - - if (cmake.contains("generator")) { - generator = toml::find(cmake, "generator").as_string(); - } - - if (cmake.contains("config")) { - config = toml::find(cmake, "config").as_string(); - } - - if (cmake.contains("arguments")) { - gen_args = detail::to_string_vec(toml::find(cmake, "arguments").as_array()); - } - } - } else { - if (toml.contains("cmake")) { - const auto &cmake = toml::find(toml, "cmake"); - cmake_version = toml::find(cmake, "minimum").as_string(); - - if (cmake.contains("description")) { - desc = toml::find(cmake, "description").as_string(); - } - - if (cmake.contains("cpp-flags")) { - cppflags = detail::to_string_vec(toml::find(cmake, "cpp-flags").as_array()); - } - - if (cmake.contains("c-flags")) { - cflags = detail::to_string_vec(toml::find(cmake, "c-flags").as_array()); - } - - if (cmake.contains("link-flags")) { - linkflags = detail::to_string_vec(toml::find(cmake, "link-flags").as_array()); - } - - if (cmake.contains("subdirs")) { - subdirs = detail::to_string_vec(toml::find(cmake, "subdirs").as_array()); - } - } - - if (toml.contains("project")) { - const auto &project = toml::find(toml, "project"); - proj_name = toml::find(project, "name").as_string(); - proj_version = toml::find(project, "version").as_string(); - } - - if (toml.contains("settings")) { - using set_map = - std::map>; - const auto &sets = toml::find(toml, "settings"); - for (const auto set : sets) { - Setting s; - s.name = set.first; - if (set.second.is_boolean()) { - s.val = set.second.as_boolean(); - } else if (set.second.is_string()) { - s.val = set.second.as_string(); - } else { - if (set.second.contains("comment")) { - s.comment = toml::find(set.second, "comment").as_string(); - } - if (set.second.contains("value")) { - auto v = toml::find(set.second, "value"); - if (v.is_boolean()) { - s.val = v.as_boolean(); - } else { - s.val = v.as_string(); - } - } - if (set.second.contains("cache")) { - s.cache = toml::find(set.second, "cache").as_boolean(); - } - if (set.second.contains("force")) { - s.force = toml::find(set.second, "force").as_boolean(); - } - } - settings.push_back(s); - } - } - - if (toml.contains("options")) { - using opts_map = - std::map>; - const auto &opts = toml::find(toml, "options"); - for (const auto opt : opts) { - Option o; - o.name = opt.first; - if (opt.second.is_boolean()) { - o.val = opt.second.as_boolean(); - } else { - if (opt.second.contains("comment")) { - o.comment = toml::find(opt.second, "comment").as_string(); - } - if (opt.second.contains("value")) { - o.val = toml::find(opt.second, "value").as_boolean(); - } - } - options.push_back(o); - } - } - - if (toml.contains("find-package")) { - using pkg_map = - std::map>; - const auto &pkgs = toml::find(toml, "find-package"); - for (const auto &pkg : pkgs) { - Package p; - p.name = pkg.first; - if (pkg.second.is_string()) { - p.version = pkg.second.as_string(); - } else { - if (pkg.second.contains("version")) { - p.version = toml::find(pkg.second, "version").as_string(); - } - if (pkg.second.contains("required")) { - p.required = toml::find(pkg.second, "required").as_boolean(); - } - if (pkg.second.contains("components")) { - p.components = - detail::to_string_vec(toml::find(pkg.second, "components").as_array()); - } - } - packages.push_back(p); - } - } - - if (toml.contains("fetch-content")) { - using content_map = std::map>; - contents = toml::find(toml, "fetch-content"); - } - - if (toml.contains("bin")) { - const auto &bins = toml::find(toml, "bin").as_array(); - - for (const auto &bin : bins) { - Bin b; - b.name = toml::find(bin, "name").as_string(); - b.type = toml::find(bin, "type").as_string(); - - b.sources = detail::to_string_vec(toml::find(bin, "sources").as_array()); - - if (bin.contains("include-dirs")) { - b.include_dirs = - detail::to_string_vec(toml::find(bin, "include-dirs").as_array()); - } - - if (bin.contains("link-libs")) { - b.link_libs = detail::to_string_vec(toml::find(bin, "link-libs").as_array()); - } - - if (bin.contains("features")) { - b.features = detail::to_string_vec(toml::find(bin, "features").as_array()); - } - - if (bin.contains("definitions")) { - b.defines = detail::to_string_vec(toml::find(bin, "definitions").as_array()); - } - - if (bin.contains("alias")) { - b.alias = toml::find(bin, "alias").as_string(); - } - - if (bin.contains("properties")) { - using prop_map = std::map; - b.properties = toml::find(bin, "properties"); - } - - binaries.push_back(b); - } - } - - if (toml.contains("test")) { - const auto &ts = toml::find(toml, "test").as_array(); - for (const auto &t : ts) { - Test test; - test.name = toml::find(t, "name").as_string(); - test.cmd = toml::find(t, "type").as_string(); - if (t.contains("arguments")) { - test.args = detail::to_string_vec(toml::find(t, "arguments").as_array()); - } - tests.push_back(test); - } - } - - if (toml.contains("install")) { - const auto &ts = toml::find(toml, "install").as_array(); - for (const auto &t : ts) { - Install inst; - if (t.contains("targets")) { - inst.targets = detail::to_string_vec(toml::find(t, "targets").as_array()); - } - if (t.contains("files")) { - inst.files = detail::to_string_vec(toml::find(t, "files").as_array()); - } - if (t.contains("dirs")) { - inst.dirs = detail::to_string_vec(toml::find(t, "dirs").as_array()); - } - if (t.contains("configs")) { - inst.configs = detail::to_string_vec(toml::find(t, "configs").as_array()); - } - inst.destination = toml::find(t, "destination").as_string(); - installs.push_back(inst); - } - } - } -} -} // namespace cmake -} // namespace cmkr diff --git a/src/cmake.hpp b/src/cmake.hpp deleted file mode 100644 index 12ff3a5..0000000 --- a/src/cmake.hpp +++ /dev/null @@ -1,84 +0,0 @@ -#pragma once - -#include -#include -#include -#include -#include - -namespace cmkr { -namespace cmake { - -struct Setting { - std::string name; - std::string comment; - mpark::variant val; - bool cache = false; - bool force = false; -}; - -struct Option { - std::string name; - std::string comment; - bool val; -}; - -struct Package { - std::string name; - std::string version; - bool required = true; - std::vector components; -}; - -struct Bin { - std::string name; - std::string type; - std::vector sources; - std::vector include_dirs; - std::vector features; - std::vector defines; - std::vector link_libs; - std::string alias; - std::map properties; -}; - -struct Test { - std::string name; - std::string cmd; - std::vector args; -}; - -struct Install { - std::vector targets; - std::vector files; - std::vector dirs; - std::vector configs; - std::string destination; -}; - -struct CMake { - std::string cmake_version = "3.15"; - std::string desc; - std::string bin_dir = "bin"; - std::string generator; - std::string config; - std::vector subdirs; - std::vector cppflags; - std::vector cflags; - std::vector linkflags; - std::vector gen_args; - std::vector build_args; - std::string proj_name; - std::string proj_version; - std::vector settings; - std::vector