From c50c4c244c5f4e0515d03a19ed853ef1df8055f0 Mon Sep 17 00:00:00 2001 From: Remy Chibois Date: Thu, 28 Dec 2023 17:34:27 +0100 Subject: [PATCH 1/4] chore: using cmade/cmate --- cpp/.gitignore | 2 + cpp/CMakeLists.txt | 26 +- cpp/Makefile | 28 +- cpp/cmake/cmade | 544 ++++++++++ cpp/cmake/cmate | 939 ++++++++++++++++++ cpp/cmate.json | 11 + cpp/deps.txt | 4 +- .../gherkin/{ => cucumber/gherkin}/app.hpp | 14 +- .../{ => cucumber/gherkin}/ast_builder.hpp | 10 +- .../{ => cucumber/gherkin}/ast_node.hpp | 12 +- .../{ => cucumber/gherkin}/builder.hpp | 6 +- .../{ => cucumber/gherkin}/cb_types.hpp | 8 +- .../gherkin}/container_helpers.hpp | 2 +- .../{ => cucumber/gherkin}/demangle.hpp | 2 +- .../{ => cucumber/gherkin}/dialect.hpp | 4 +- .../{ => cucumber/gherkin}/exceptions.hpp | 6 +- .../gherkin/{ => cucumber/gherkin}/file.hpp | 2 +- .../{ => cucumber/gherkin}/id_generator.hpp | 2 +- .../gherkin/{ => cucumber/gherkin}/items.hpp | 2 +- .../{ => cucumber/gherkin}/join_utils.hpp | 4 +- .../{ => cucumber/gherkin}/keywords.hpp | 4 +- .../gherkin/{ => cucumber/gherkin}/line.hpp | 6 +- .../gherkin/{ => cucumber/gherkin}/log.hpp | 2 +- .../{ => cucumber/gherkin}/msg_types.hpp | 2 +- .../{ => cucumber/gherkin}/parse_error.hpp | 2 +- .../gherkin/{ => cucumber/gherkin}/parser.hpp | 6 +- .../{ => cucumber/gherkin}/parser_base.hpp | 12 +- .../{ => cucumber/gherkin}/parser_context.hpp | 10 +- .../{ => cucumber/gherkin}/parser_info.hpp | 2 +- .../gherkin}/pickle_compiler.hpp | 12 +- .../gherkin}/pickle_compiler_context.hpp | 10 +- .../gherkin/{ => cucumber/gherkin}/regex.hpp | 10 +- .../{ => cucumber/gherkin}/rule_type.hpp | 2 +- .../gherkin/{ => cucumber/gherkin}/sink.hpp | 2 +- .../gherkin/{ => cucumber/gherkin}/token.hpp | 12 +- .../gherkin}/token_formatter_builder.hpp | 10 +- .../{ => cucumber/gherkin}/token_matcher.hpp | 12 +- .../{ => cucumber/gherkin}/token_scanner.hpp | 8 +- .../gherkin/cucumber/gherkin/type_traits.hpp | 32 + .../gherkin/{ => cucumber/gherkin}/types.hpp | 2 +- .../gherkin/{ => cucumber/gherkin}/utils.hpp | 2 +- cpp/include/gherkin/type_traits.hpp | 38 - .../gherkin-generate-tokens/CMakeLists.txt | 23 +- .../bin/gherkin-generate-tokens/cmate.json | 7 + .../gherkin-generate-tokens.cpp | 16 +- cpp/src/bin/gherkin/CMakeLists.txt | 23 +- cpp/src/bin/gherkin/cmate.json | 7 + cpp/src/bin/gherkin/gherkin.cpp | 10 +- cpp/src/lib/gherkin/CMakeLists.txt | 37 +- cpp/src/lib/gherkin/cmate.json | 8 + .../gherkin/{ => cucumber/gherkin}/app.cpp | 10 +- .../{ => cucumber/gherkin}/ast_builder.cpp | 10 +- .../{ => cucumber/gherkin}/ast_node.cpp | 4 +- .../{ => cucumber/gherkin}/demangle.cpp | 4 +- .../{ => cucumber/gherkin}/dialect.cpp | 4 +- .../{ => cucumber/gherkin}/exceptions.cpp | 8 +- .../{ => cucumber/gherkin}/id_generator.cpp | 4 +- .../{ => cucumber/gherkin}/keywords.cpp | 6 +- .../gherkin/{ => cucumber/gherkin}/line.cpp | 10 +- .../{ => cucumber/gherkin}/parse_error.cpp | 4 +- .../gherkin}/pickle_compiler.cpp | 8 +- .../gherkin}/pickle_compiler_context.cpp | 4 +- .../gherkin/{ => cucumber/gherkin}/regex.cpp | 4 +- .../{ => cucumber/gherkin}/rule_type.cpp | 4 +- .../gherkin/{ => cucumber/gherkin}/token.cpp | 4 +- .../gherkin}/token_formatter_builder.cpp | 6 +- .../{ => cucumber/gherkin}/token_matcher.cpp | 16 +- .../{ => cucumber/gherkin}/token_scanner.cpp | 8 +- .../gherkin/{ => cucumber/gherkin}/utils.cpp | 4 +- 69 files changed, 1797 insertions(+), 282 deletions(-) create mode 100755 cpp/cmake/cmade create mode 100755 cpp/cmake/cmate create mode 100644 cpp/cmate.json rename cpp/include/gherkin/{ => cucumber/gherkin}/app.hpp (70%) rename cpp/include/gherkin/{ => cucumber/gherkin}/ast_builder.hpp (91%) rename cpp/include/gherkin/{ => cucumber/gherkin}/ast_node.hpp (92%) rename cpp/include/gherkin/{ => cucumber/gherkin}/builder.hpp (85%) rename cpp/include/gherkin/{ => cucumber/gherkin}/cb_types.hpp (84%) rename cpp/include/gherkin/{ => cucumber/gherkin}/container_helpers.hpp (97%) rename cpp/include/gherkin/{ => cucumber/gherkin}/demangle.hpp (91%) rename cpp/include/gherkin/{ => cucumber/gherkin}/dialect.hpp (91%) rename cpp/include/gherkin/{ => cucumber/gherkin}/exceptions.hpp (95%) rename cpp/include/gherkin/{ => cucumber/gherkin}/file.hpp (71%) rename cpp/include/gherkin/{ => cucumber/gherkin}/id_generator.hpp (95%) rename cpp/include/gherkin/{ => cucumber/gherkin}/items.hpp (81%) rename cpp/include/gherkin/{ => cucumber/gherkin}/join_utils.hpp (95%) rename cpp/include/gherkin/{ => cucumber/gherkin}/keywords.hpp (77%) rename cpp/include/gherkin/{ => cucumber/gherkin}/line.hpp (88%) rename cpp/include/gherkin/{ => cucumber/gherkin}/log.hpp (97%) rename cpp/include/gherkin/{ => cucumber/gherkin}/msg_types.hpp (94%) rename cpp/include/gherkin/{ => cucumber/gherkin}/parse_error.hpp (90%) rename cpp/include/gherkin/{ => cucumber/gherkin}/parser.hpp (99%) rename cpp/include/gherkin/{ => cucumber/gherkin}/parser_base.hpp (82%) rename cpp/include/gherkin/{ => cucumber/gherkin}/parser_context.hpp (85%) rename cpp/include/gherkin/{ => cucumber/gherkin}/parser_info.hpp (87%) rename cpp/include/gherkin/{ => cucumber/gherkin}/pickle_compiler.hpp (89%) rename cpp/include/gherkin/{ => cucumber/gherkin}/pickle_compiler_context.hpp (54%) rename cpp/include/gherkin/{ => cucumber/gherkin}/regex.hpp (95%) rename cpp/include/gherkin/{ => cucumber/gherkin}/rule_type.hpp (96%) rename cpp/include/gherkin/{ => cucumber/gherkin}/sink.hpp (83%) rename cpp/include/gherkin/{ => cucumber/gherkin}/token.hpp (76%) rename cpp/include/gherkin/{ => cucumber/gherkin}/token_formatter_builder.hpp (79%) rename cpp/include/gherkin/{ => cucumber/gherkin}/token_matcher.hpp (90%) rename cpp/include/gherkin/{ => cucumber/gherkin}/token_scanner.hpp (84%) create mode 100644 cpp/include/gherkin/cucumber/gherkin/type_traits.hpp rename cpp/include/gherkin/{ => cucumber/gherkin}/types.hpp (94%) rename cpp/include/gherkin/{ => cucumber/gherkin}/utils.hpp (99%) delete mode 100644 cpp/include/gherkin/type_traits.hpp create mode 100644 cpp/src/bin/gherkin-generate-tokens/cmate.json create mode 100644 cpp/src/bin/gherkin/cmate.json create mode 100644 cpp/src/lib/gherkin/cmate.json rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/app.cpp (87%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/ast_builder.cpp (98%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/ast_node.cpp (91%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/demangle.cpp (85%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/dialect.cpp (99%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/exceptions.cpp (96%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/id_generator.cpp (75%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/keywords.cpp (90%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/line.cpp (95%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/parse_error.cpp (74%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/pickle_compiler.cpp (98%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/pickle_compiler_context.cpp (71%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/regex.cpp (93%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/rule_type.cpp (96%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/token.cpp (70%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/token_formatter_builder.cpp (91%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/token_matcher.cpp (95%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/token_scanner.cpp (86%) rename cpp/src/lib/gherkin/{ => cucumber/gherkin}/utils.cpp (92%) diff --git a/cpp/.gitignore b/cpp/.gitignore index 5abb1e17c..8418e80fc 100644 --- a/cpp/.gitignore +++ b/cpp/.gitignore @@ -2,6 +2,8 @@ ext/ build/ acceptance/ stage/ +.cmade/ +.cmate/ .built .configured .deps-installed diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 85bc7d396..2c00dcb6b 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,16 +1,16 @@ cmake_minimum_required(VERSION 3.12 FATAL_ERROR) -project(gherkin-cpp VERSION 1.0.0 LANGUAGES C CXX) +project(cucumber_gherkin VERSION 1.0.0 LANGUAGES C CXX) include(GNUInstallDirs) -set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_POSITION_INDEPENDENT_CODE ON) find_package(nlohmann_json CONFIG REQUIRED) -find_package(cucumber-messages CONFIG REQUIRED) +find_package(cucumber_messages CONFIG REQUIRED) add_subdirectory(src/lib/gherkin) add_subdirectory(src/bin/gherkin) @@ -18,23 +18,23 @@ add_subdirectory(src/bin/gherkin-generate-tokens) install( TARGETS - gherkin-cpp - gherkin-bin - gherkin-generate-tokens-bin - EXPORT gherkin-cpp-config + cucumber_gherkin_lib + cucumber_gherkin_bin + cucumber_gherkin_generate_tokens_bin + EXPORT cucumber_gherkin-config RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} ) install( - DIRECTORY "${CMAKE_SOURCE_DIR}/include/" - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/gherkin + EXPORT cucumber_gherkin-config + FILE cucumber_gherkin-config.cmake + NAMESPACE cucumber:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/cucumber_gherkin ) install( - EXPORT gherkin-cpp-config - FILE gherkin-cpp-config.cmake - NAMESPACE gherkin-cpp:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/gherkin-cpp + DIRECTORY "${PROJECT_SOURCE_DIR}/include/gherkin/" + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/cucumber ) diff --git a/cpp/Makefile b/cpp/Makefile index 8bbb0c5ef..159492366 100644 --- a/cpp/Makefile +++ b/cpp/Makefile @@ -1,10 +1,12 @@ SHELL := /usr/bin/env bash +SUB_DIR = gherkin/cucumber/gherkin + GRAMMAR_GENERATED = \ - include/gherkin/rule_type.hpp \ - include/gherkin/parser.hpp + include/$(SUB_DIR)/rule_type.hpp \ + include/$(SUB_DIR)/parser.hpp LANGUAGE_GENERATED = \ - src/lib/gherkin/dialect.cpp + src/lib/$(SUB_DIR)/dialect.cpp ALL_GENERATED := $(GRAMMAR_GENERATED) $(LANGUAGE_GENERATED) ALL_SOURCE_FILES = $(shell find include src -name "*.[ch]*") SOURCE_FILES := $(filter-out $(ALL_GENERATED),$(ALL_SOURCE_FILES)) @@ -53,32 +55,24 @@ clean: clean-deps ## Remove all build artifacts and files generated by the accep acceptance: .built $(TOKENS) $(ASTS) $(PICKLES) $(ERRORS) $(SOURCES) ## Build acceptance test dir and compare results with reference .built: .configured $(SOURCE_FILES) - cmake --build build/gherkin --parallel $(NPROCS) - cmake --install build/gherkin + ./cmake/cmate build touch $@ .configured: .deps-installed - rm -rf build/gherkin && mkdir -p build/gherkin - cmake \ - -G Ninja \ - -DCMAKE_PREFIX_PATH=$(CMAKE_BUILDROOT) \ - -DCMAKE_INSTALL_PREFIX=$(HERE)/stage \ - -S . \ - -B build/gherkin \ - --toolchain cmake/toolchains/ext.cmake + ./cmake/cmate configure touch $@ define berp-generate-parser = berp -g ../gherkin.berp -t $< -o $@ --noBOM endef -include/gherkin/rule_type.hpp: gherkin-cpp-rule-type.razor ../gherkin.berp +include/$(SUB_DIR)/rule_type.hpp: gherkin-cpp-rule-type.razor ../gherkin.berp $(berp-generate-parser) -include/gherkin/parser.hpp: gherkin-cpp-parser.razor ../gherkin.berp +include/$(SUB_DIR)/parser.hpp: gherkin-cpp-parser.razor ../gherkin.berp $(berp-generate-parser) -src/lib/gherkin/dialect.cpp: ../gherkin-languages.json dialect.cpp.jq +src/lib/$(SUB_DIR)/dialect.cpp: ../gherkin-languages.json dialect.cpp.jq jq -f dialect.cpp.jq -r -c < $< > $@ acceptance/testdata/%.tokens: ../testdata/% ../testdata/%.tokens @@ -113,7 +107,7 @@ install-deps: .deps-installed .PHONY: install-deps .deps-installed: - ./scripts/build-externals deps.txt + ./cmake/cmade install touch $@ clean-deps: diff --git a/cpp/cmake/cmade b/cpp/cmake/cmade new file mode 100755 index 000000000..bf62d492b --- /dev/null +++ b/cpp/cmake/cmade @@ -0,0 +1,544 @@ +#!/usr/bin/env -S cmake -P +# -*- CMake -*- + +set(CMADE "cmade") +set(CMADE_DEPSFILE "deps.txt") +set(CMADE_VERSION "X.Y.Z") +list( + APPEND + CMADE_VARS + "CMADE_GIT_HOST=GH" + "CMADE_GH=https://github.com" + "CMADE_GL=https://gitlab.com" + "CMADE_BB=https://bitbucket.org" +) +list( + APPEND + CMADE_OPTIONS + "verbose" + "simulate" + "no-cache" +) + + +############################################################################## +# +# Utility functions +# +############################################################################## +function(cmade_show_help) + message("\ +CMake Dependency Installer v${CMADE_VERSION} + +usage: ${CMADE} [OPTIONS] COMMAND + +Options: + --verbose Verbose operation + --simulate Echo commands instead of running them + --no-cache Ignore/erase existing repositories + +Commands: + install Install dependencies from ${CMADE_DEPSFILE} + clean Clean local environment + help Display this information +") +endfunction() + +function(cmade_die MSG) + message(FATAL_ERROR "CMade: error: ${MSG}") +endfunction() + +function(cmade_msg MSG) + message("CMade: ${MSG}") +endfunction() + +function(cmade_info MSG) + if(CMADE_VERBOSE) + cmade_msg(${MSG}) + endif() +endfunction() + +function(cmade_setg VAR VAL) + set(${VAR} "${VAL}" CACHE INTERNAL "${VAR}") +endfunction() + +function(cmade_run_prog) + cmake_parse_arguments(RUN "" "DIR" "CMD" ${ARGN}) + + if(CMADE_SIMULATE) + list(PREPEND RUN_CMD "echo") + endif() + + execute_process( + COMMAND ${RUN_CMD} + WORKING_DIRECTORY "${RUN_DIR}" + RESULTS_VARIABLE RC + ) + + if(RC) + list(JOIN ARGV " " RUN_CMD) + cmade_die("command failed: ${RUN_CMD}") + endif() +endfunction() + +function(cmade_download URL FILE) + if(CMADE_SIMULATE) + cmade_msg("download ${URL} to ${FILE}") + else() + file(DOWNLOAD ${URL} ${FILE} STATUS ST) + endif() + + list(GET ST 0 RC) + + if(RC) + cmade_die("download of ${URL} failed: ${ST}") + endif() +endfunction() + +function(cmade_unique_dir PATH VAR) + file(GLOB PATHS "${PATH}/*") + + foreach(PATH ${PATHS}) + if(IS_DIRECTORY ${PATH}) + list(APPEND ALL_DIRS ${PATH}) + endif() + endforeach() + + list(LENGTH ALL_DIRS DIRS) + + if(DIRS EQUAL 0) + cmade_die("no directories found in ${PATH}") + elseif(DIRS GREATER 1) + cmade_die("multiple directories found ${PATH}") + endif() + + list(GET ALL_DIRS 0 DIR) + set(${VAR} ${DIR} PARENT_SCOPE) +endfunction() + +function(cmade_set_cache_dir NAME) + string(REPLACE "/" "_" DIR ${NAME}) + set(DIR "${CMADE_CACHE}/${DIR}") + cmade_setg(CMADE_CACHE_DIR ${DIR}) + cmade_setg(CMADE_SOURCE_DIR "${DIR}/sources") + cmade_setg(CMADE_BUILD_DIR "${DIR}/build") + cmade_setg(CMADE_STATE_DIR "${DIR}/state") + + if(CMADE_NO_CACHE) + file(REMOVE_RECURSE "${DIR}") + endif() +endfunction() + +function(cmade_state_file STATE VAR) + set(${VAR} "${CMADE_STATE_DIR}/.${STATE}" PARENT_SCOPE) +endfunction() + +function(cmade_set_state STATE) + file(MAKE_DIRECTORY ${CMADE_STATE_DIR}) + cmade_state_file(${STATE} FILE) + file(TOUCH ${FILE}) +endfunction() + +function(cmade_fetch_repo HOST REPO REF) + if(HOST MATCHES "^\\$\\{(.+)\\}$") + # Dereference variable + set(HOST ${${CMAKE_MATCH_1}}) + endif() + + if(HOST STREQUAL "GH") + set(HOST "https://github.com") + elseif(TYPE STREQUAL "GL") + set(HOST "https://gitlab.com") + endif() + + set(URL "${HOST}/${REPO}.git") + + set(GIT_ARGS "clone") + list( + APPEND GIT_ARGS + -c advice.detachedHead=false + --depth 1 + ) + + if(REF) + list(APPEND GIT_ARGS --branch "${REF}") + endif() + + cmade_set_cache_dir(${REPO}) + cmade_state_file("fetched" FETCHED) + + if(NOT IS_DIRECTORY ${CMADE_SOURCE_DIR} OR NOT EXISTS ${FETCHED}) + # Whatever the reason, we're (re-)fetching + file(REMOVE_RECURSE ${CMADE_SOURCE_DIR}) + cmade_info("cloning ${URL} in ${CMADE_SOURCE_DIR}") + cmade_run_prog(CMD git ${GIT_ARGS} ${URL} ${CMADE_SOURCE_DIR}) + cmade_set_state("fetched") + endif() +endfunction() + +function(cmade_fetch_url URL) + string(MD5 HASH ${URL}) + + if(URL MATCHES "/([^/]+)$") + set(FILE ${CMAKE_MATCH_1}) + else() + cmade_die("can't find filename from URL: ${URL}") + endif() + + cmade_set_cache_dir(${HASH}) + cmade_state_file("fetched" FETCHED) + cmade_state_file("extracted" EXTRACTED) + set(CFILE "${CMADE_CACHE_DIR}/${FILE}") + + if(NOT EXISTS ${CFILE}) + cmade_info("downloading ${URL} in ${CDIR}") + cmade_download(${URL} ${CFILE}) + cmade_set_state("fetched") + endif() + + if(NOT IS_DIRECTORY ${CMADE_SOURCE_DIR} OR NOT EXISTS ${EXTRACTED}) + file(REMOVE_RECURSE ${CMADE_SOURCE_DIR}) + cmade_info("extracting ${FILE}") + file( + ARCHIVE_EXTRACT + INPUT ${CFILE} + DESTINATION ${CMADE_SOURCE_DIR} + ) + cmade_set_state("extracted") + endif() + + cmade_unique_dir(${CMADE_SOURCE_DIR} SDIR) + cmade_setg(CMADE_SOURCE_DIR ${SDIR}) +endfunction() + +############################################################################## +# +# Dependency installation functions +# +############################################################################## +function(cmade_build_cmake_dep) + cmade_state_file("configured" CONFIGURED) + cmade_state_file("built" BUILT) + cmade_state_file("installed" INSTALLED) + + cmade_msg("building with: ${ARGV}") + + if(NOT EXISTS ${CONFIGURED}) + set(ARGS "") + + find_program(CMADE_CCACHE ccache) + + if(CMATE_CCACHE) + list(APPEND ARGS "-DCMAKE_C_COMPILER_LAUNCHER=${CMADE_CCACHE}") + list(APPEND ARGS "-DCMAKE_CXX_COMPILER_LAUNCHER=${CMADE_CCACHE}") + endif() + + find_program(CMADE_NINJA ninja) + + if(CMADE_NINJA) + list(APPEND ARGS "-G" "Ninja") + endif() + + cmade_run_prog( + CMD + ${CMAKE_COMMAND} + -DCMAKE_PREFIX_PATH=${CMADE_ENV} + -DCMAKE_INSTALL_PREFIX=${CMADE_ENV} + -DCMAKE_BUILD_TYPE:STRING=Release + ${ARGS} + -S ${CMADE_SOURCE_DIR} -B ${CMADE_BUILD_DIR} + ${ARGV} + ) + cmade_set_state("configured") + endif() + if(NOT EXISTS ${BUILT}) + cmade_run_prog(CMD ${CMAKE_COMMAND} --build ${CMADE_BUILD_DIR} --parallel) + cmade_set_state("built") + endif() + if(NOT EXISTS ${INSTALLED}) + cmade_run_prog(CMD ${CMAKE_COMMAND} --install ${CMADE_BUILD_DIR}) + cmade_set_state("installed") + endif() +endfunction() + +function(cmade_build_meson_dep) + cmade_state_file("configured" CONFIGURED) + cmade_state_file("installed" INSTALLED) + file(MAKE_DIRECTORY ${CMADE_BUILD_DIR}) + + if(NOT EXISTS ${CONFIGURED}) + cmade_run_prog( + DIR ${CMADE_BUILD_DIR} + CMD + meson + --prefix=${CMADE_ENV} + --pkg-config-path=${CMADE_ENV} + --cmake-prefix-path=${CMADE_ENV} + ${ARGV} + . ${SRCDIR} + ) + cmade_set_state("configured") + endif() + if(NOT EXISTS ${INSTALLED}) + cmade_run_prog(meson install) + cmade_set_state("installed") + endif() +endfunction() + +function(cmade_build_autotools_dep) + cmade_state_file("configured" CONFIGURED) + cmade_state_file("installed" INSTALLED) + file(MAKE_DIRECTORY ${CMADE_BUILD_DIR}) + + if(NOT EXISTS ${CONFIGURED}) + cmade_run_prog( + DIR ${CMADE_BUILD_DIR} + CMD + ${CMADE_SOURCE_DIR}/configure + --prefix=${CMADE_ENV} + ${ARGV} + ) + cmade_set_state("configured") + endif() + if(NOT EXISTS ${INSTALLED}) + cmade_run_prog( + DIR ${CMADE_BUILD_DIR} + CMD make install + ) + cmade_set_state("installed") + endif() +endfunction() + +function(cmade_build_makefile_dep) + cmade_state_file("built" BUILT) + cmade_state_file("installed" INSTALLED) + file(MAKE_DIRECTORY ${CMADE_BUILD_DIR}) + + if(NOT EXISTS ${BUILT}) + cmade_run_prog( + DIR ${CMADE_SOURCE_DIR} + CMD make + ) + cmade_set_state("built") + endif() + if(NOT EXISTS ${INSTALLED}) + cmade_run_prog( + DIR ${CMADE_SOURCE_DIR} + CMD make prefix=${CMADE_ENV} install + ) + cmade_set_state("installed") + endif() +endfunction() + +function(cmade_build_dep ARGS) + set(OPT_PROC ON) + string(REGEX MATCHALL "[^ \"']+|\"([^\"]*)\"|'([^']*)'" ARGS "${ARGS}") + + foreach(ARG ${ARGS}) + if(OPT_PROC AND ARG MATCHES "^--") + if(ARG STREQUAL "--") + set(OPT_PROC OFF) + elseif(ARG MATCHES "^--srcdir=(.+)") + cmade_setg( + CMADE_SOURCE_DIR + "${CMADE_SOURCE_DIR}/${CMAKE_MATCH_1}" + ) + endif() + else() + list(APPEND CONF_ARGS ${ARG}) + endif() + endforeach() + + if(NOT IS_DIRECTORY "${CMADE_SOURCE_DIR}") + cmade_die("invalid source directory: ${CMADE_SOURCE_DIR}") + endif() + + if(EXISTS "${CMADE_SOURCE_DIR}/CMakeLists.txt") + cmade_build_cmake_dep(${CONF_ARGS}) + elseif(EXISTS "${CMADE_SOURCE_DIR}/meson.build") + cmade_build_meson_dep(${CONF_ARGS}) + elseif(EXISTS "${CMADE_SOURCE_DIR}/configure") + cmade_build_autotools_dep(${CONF_ARGS}) + elseif(EXISTS "${CMADE_SOURCE_DIR}/Makefile") + cmade_build_makefile_dep(${CONF_ARGS}) + else() + cmade_die("don't know how to build in ${CMADE_SOURCE_DIR}") + endif() +endfunction() + +function(cmade_install_repo HOST REPO TAG ARGS) + cmade_fetch_repo(${HOST} ${REPO} "${TAG}") + cmade_build_dep("${ARGS}") +endfunction() + +function(cmade_install_url URL ARGS) + cmade_fetch_url(${URL}) + cmade_build_dep("${ARGS}") +endfunction() + +function(cmade_install) + if(NOT EXISTS ${CMADE_DEPSFILE}) + cmade_msg("no dependencies") + return() + endif() + + file(STRINGS ${CMADE_DEPSFILE} DEPS) + + foreach(SPEC ${DEPS}) + if(SPEC MATCHES "^#") + # Skip comments + continue() + elseif(SPEC MATCHES "^([A-Za-z0-9_-]+)=(.+)$") + # Variable assignment + cmade_setg("CMADE_${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}") + elseif(SPEC MATCHES "^([a-z]+://[^ ]+)([ ](.+))?$") + # URL + set(URL ${CMAKE_MATCH_1}) + set(ARGS "${CMAKE_MATCH_3}") + cmade_msg("checking ${URL}") + cmade_install_url(${URL} "${ARGS}") + elseif(SPEC MATCHES "^(([^: ]+):)?([^@ ]+)(@([^ ]+))?([ ](.+))?$") + # GitHub/GitLab style project short ref + if(CMAKE_MATCH_2) + if(CMADE_${CMAKE_MATCH_2}) + set(HOST ${CMADE_${CMAKE_MATCH_2}}) + else() + cmade_die("unknown id: ${CMAKE_MATCH_2}") + endif() + else() + set(HOST ${CMADE_${CMADE_GIT_HOST}}) + endif() + + set(REPO ${CMAKE_MATCH_3}) + set(TAG ${CMAKE_MATCH_5}) + set(ARGS "${CMAKE_MATCH_7}") + cmade_msg("checking ${REPO}") + cmade_install_repo(${HOST} ${REPO} "${TAG}" "${ARGS}") + else() + cmade_die("invalid dependency line: ${SPEC}") + endif() + endforeach() +endfunction() + +############################################################################## +# +# Environment cleaning functions +# +############################################################################## +function(cmade_clean) + cmade_msg("cleaning: ${CMADE_ROOT}") + + if (IS_DIRECTORY ${CMADE_ROOT}) + file(REMOVE_RECURSE ${CMADE_ROOT}) + endif() +endfunction() + +############################################################################## +# +# Argument functions +# +############################################################################## +function(cmade_locate_cmade_arguments) + set(FOUND OFF) + + foreach(POS RANGE ${CMAKE_ARGC}) + string(TOLOWER "${CMAKE_ARGV${POS}}" ARG) + math(EXPR POS "${POS}+1") + + if (ARG MATCHES "${CMADE}$") + # Script args follow us, POS already incremented + set(FOUND ON) + cmade_setg(CMADE_POS ${POS}) + break() + endif() + endforeach() + + if(NOT FOUND) + # Should not happen if script has correct name (see CMADE at top) + cmade_die("parse_argument") + endif() +endfunction() + +function(cmade_parse_arguments) + cmade_locate_cmade_arguments() + + while(CMADE_POS LESS ${CMAKE_ARGC}) + if ("${CMAKE_ARGV${CMADE_POS}}" MATCHES "--?([A-Za-z0-9_-]+)") + list(FIND CMADE_OPTIONS ${CMAKE_MATCH_1} OPT) + + if (OPT LESS 0) + cmade_die("unknown option: ${CMAKE_MATCH_1}") + else() + string(TOUPPER "CMADE_${CMAKE_MATCH_1}" OPT) + string(REPLACE "-" "_" OPT "${OPT}") + cmade_setg(${OPT} 1) + endif() + else() + list(APPEND CMADE_ARGS "${CMAKE_ARGV${CMADE_POS}}") + endif() + + math(EXPR CMADE_POS "${CMADE_POS}+1") + endwhile() + + list(LENGTH CMADE_ARGS CMADE_ARGC) + + if (CMADE_ARGC GREATER 0) + list(POP_FRONT CMADE_ARGS CMADE_CMD) + cmade_setg(CMADE_CMD "${CMADE_CMD}") + endif() + + cmade_setg(CMADE_ARGS "${CMADE_ARGS}") + get_filename_component(CMADE_ENV "${CMADE_ENV}" REALPATH) + cmade_setg(CMADE_ENV ${CMADE_ENV}) +endfunction() + +############################################################################## +# +# Default variables +# +############################################################################## +function(cmade_set_vars) + get_filename_component(DIR ".cmade" ABSOLUTE) + cmade_setg(CMADE_ROOT ${DIR}) + get_filename_component(DIR "cache" ABSOLUTE BASE_DIR ${CMADE_ROOT}) + cmade_setg(CMADE_CACHE ${DIR}) + get_filename_component(DIR "env" ABSOLUTE BASE_DIR ${CMADE_ROOT}) + cmade_setg(CMADE_ENV ${DIR}) + + foreach(VDEF ${CMADE_VARS}) + if(VDEF MATCHES "^CMADE_([^=]+)=(.*)$") + cmade_info("default: ${CMAKE_MATCH_1}=${CMAKE_MATCH_2}") + cmade_setg("CMADE_${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}") + endif() + endforeach() +endfunction() + +############################################################################## +# +# Command processing +# +############################################################################## +function(cmade_process_cmd) + if (CMADE_CMD STREQUAL "version") + message(${CMADE_VERSION}) + elseif (CMADE_CMD STREQUAL "install") + cmade_install() + elseif (CMADE_CMD STREQUAL "clean") + cmade_clean() + elseif (CMADE_CMD STREQUAL "help") + cmade_show_help() + elseif(CMADE_CMD) + cmade_msg("unknown command: ${CMADE_CMD}") + elseif(NOT CMADE_CMD) + cmade_msg("no command") + endif() +endfunction() + +############################################################################## +# +# Main part +# +############################################################################## +cmade_parse_arguments() +cmade_set_vars() +cmade_process_cmd() diff --git a/cpp/cmake/cmate b/cpp/cmake/cmate new file mode 100755 index 000000000..8ff0d4de7 --- /dev/null +++ b/cpp/cmake/cmate @@ -0,0 +1,939 @@ +#!/usr/bin/env -S cmake -P +# -*- CMake -*- + +set(CMATE "cmate") +set(CMATE_VER "X.Y.Z") +set(CMATE_CONF "cmate.json") +cmake_policy(SET CMP0057 NEW) +list( + APPEND + CMATE_CMDS + "configure" + "build" + "stage" + "clean" +) +list( + APPEND + CMATE_OPTIONS + "verbose" +) +list( + APPEND + CMATE_CONFIGURE_OPTIONS + "dry-run" + "dump" + "namespace" + "version" + "version-file" + "source-pat" + "header-pat" +) +############################################################################## +# +# Help messages +# +############################################################################## +set(CMATE_HELP_HEADER "CMake Automatic TargEts v${CMATE_VER}") + +# Generic help +set( + CMATE_HELP + " +Usage: cmate [OPTIONS] COMMAND + +Options: + --verbose Verbose operation + +Commands: + configure Scans and configures targets + build + clean + stage + help Display this information + +See 'cmate help ' to read about a specific subcommand." +) + +# Configure help +set( + CMATE_CONFIGURE_HELP + " +Usage: cmate configure [OPTIONS] + +Configure local project + +Options: + --dry-run Don't touch anything + --dump Dump generated CMakeLists.txt + --namespace=NS CMake package namespace + --version=SEMVER CMake package version + --version-file=FILE CMake package version from FILE + --version-file=FILE CMake package version from FILE + --source-pat=PATTERN CMate targets source file glob pattern + (default: \$CACHE{CMATE_SOURCE_PAT}) + --header-pat=PATTERN CMate targets header file glob pattern + (default: \$CACHE{CMATE_HEADER_PAT})" +) + +# Build help +set( + CMATE_BUILD_HELP + " +Usage: cmate build + +Build local project" +) + +# Stage help +set( + CMATE_STAGE_HELP + " +Usage: cmate stage + +Stage local project" +) + +# Clean help +set( + CMATE_CLEAN_HELP + " +Usage: cmate clean + +Clean local project" +) +############################################################################## +# +# Targets +# +############################################################################## +set(CMATE_TARGETS "") + +############################################################################## +# +# Utility functions +# +############################################################################## +function(cmate_show_help) + set(HVAR "CMATE") + if(CMATE_ARGC GREATER 0) + list(GET CMATE_ARGS 0 HCMD) + + if(${HCMD} IN_LIST CMATE_CMDS) + string(TOUPPER "${HCMD}" HCMD) + string(APPEND HVAR "_${HCMD}") + else() + cmate_die("no such command: ${HCMD}") + endif() + endif() + + string(APPEND HVAR "_HELP") + string(CONFIGURE ${${HVAR}} HELP) + + message("${CMATE_HELP_HEADER}") + message(${HELP}) +endfunction() + +function(cmate_die MSG) + message(FATAL_ERROR "CMate: error: ${MSG}") +endfunction() + +function(cmate_msg) + list(JOIN ARGV "" MSGS) + message("CMate: ${MSGS}") +endfunction() + +function(cmate_warn MSG) + message(WARNING "CMate: ${MSG}") +endfunction() + +function(cmate_info MSG) + if(CMATE_VERBOSE) + cmate_msg(${MSG}) + endif() +endfunction() + +function(cmate_setg VAR VAL) + set(${VAR} "${VAL}" CACHE INTERNAL "${VAR}") +endfunction() + +function(cmate_state_file STATE VAR) + set(${VAR} "${CMATE_STATE_DIR}/.${STATE}" PARENT_SCOPE) +endfunction() + +function(cmate_clear_state STATE) + file(MAKE_DIRECTORY ${CMATE_STATE_DIR}) + cmate_state_file(${STATE} FILE) + file(REMOVE ${FILE}) +endfunction() + +function(cmate_set_state STATE) + file(MAKE_DIRECTORY ${CMATE_STATE_DIR}) + cmate_state_file(${STATE} FILE) + file(TOUCH ${FILE}) +endfunction() + +function(cmate_clear_states) + if (IS_DIRECTORY ${CMATE_STATE_DIR}) + file(REMOVE_RECURSE ${CMATE_STATE_DIR}) + endif() +endfunction() + +function(cmate_load_version) + if(NOT "${CMATE_VERSION}" STREQUAL "") + return() + endif() + + if("${CMATE_VERSION_FILE}" STREQUAL "") + cmate_setg( + CMATE_VERSION_FILE + "${CMATE_ROOT_DIR}/version.txt" + ) + endif() + + if(EXISTS ${CMATE_VERSION_FILE}) + file( + STRINGS ${CMATE_VERSION_FILE} VER + REGEX "^[^\\.]+\\.[^\\.]+\\.[^\\.]+$" + LIMIT_COUNT 1 + ) + + cmate_setg(CMATE_VERSION ${VER}) + endif() +endfunction() + +function(cmate_set_version) + cmate_load_version() + + if("${CMATE_VERSION}" STREQUAL "") + cmate_warn("using default version: 0.1.0") + cmate_setg(CMATE_VERSION "0.1.0") + endif() + + if("${CMATE_VERSION}" MATCHES "^([^\\.]+)\\.([^\\.]+)\\.([^\\.]+)$") + cmate_setg(CMATE_VERSION_MAJOR ${CMAKE_MATCH_1}) + cmate_setg(CMATE_VERSION_MINOR ${CMAKE_MATCH_2}) + cmate_setg(CMATE_VERSION_PATCH ${CMAKE_MATCH_3}) + else() + cmate_die("unable to parse version: ${CMATE_VERSION}") + endif() +endfunction() + +macro(cmate_setv VAR VAL) + if("${${VAR}}" STREQUAL "") + set(${VAR} ${VAL}) + endif() +endmacro() + +function(cmate_json_get_array JSON KEY VAR) + string(JSON ARRAY ERROR_VARIABLE ERR GET ${JSON} ${KEY}) + set(ITEMS "") + + if (NOT ERR) + string(JSON N LENGTH ${ARRAY}) + + if(${N} GREATER_EQUAL 1) + math(EXPR N "${N}-1") + + foreach(I RANGE ${N}) + string(JSON ITEM GET ${ARRAY} ${I}) + list(APPEND ITEMS ${ITEM}) + endforeach() + endif() + endif() + + set(${VAR} ${ITEMS} PARENT_SCOPE) +endfunction() + +function(cmate_load_cmake_package_deps JSON PREFIX) + cmate_json_get_array("${JSON}" "cmake" "PKGS") + set(PACKAGES "") + + foreach(PKG ${PKGS}) + set(PKGTYPE "STRING") + + if("${PKG}" MATCHES "^[[{].*$") + string(JSON PKGTYPE TYPE ${PKG}) + endif() + + if(${PKGTYPE} STREQUAL "STRING") + # Simple module + list(APPEND PACKAGES ${PKG}) + elseif(${PKGTYPE} STREQUAL "OBJECT") + # Module and components + string(JSON PKGNAME MEMBER ${PKG} 0) + list(APPEND PACKAGES ${PKGNAME}) + + cmate_json_get_array(${PKG} ${PKGNAME} "COMPS") + + set("${PREFIX}_CMAKE_${PKGNAME}_COMPS" ${COMPS} PARENT_SCOPE) + endif() + endforeach() + + set("${PREFIX}_CMAKE_PACKAGES" ${PACKAGES} PARENT_SCOPE) +endfunction() + +function(cmate_load_pkgconfig_package_deps JSON PREFIX) + cmate_json_get_array("${JSON}" "pkgconfig" "PKGS") + set("${PREFIX}_PKGCONFIG_PACKAGES" ${PKGS} PARENT_SCOPE) +endfunction() + +function(cmate_load_conf FILE) + set(PKGS "") + + if(EXISTS ${FILE}) + file(READ ${FILE} JSON) + + string(JSON PROJECT GET ${JSON} "name") + cmate_setg(CMATE_PROJECT ${PROJECT}) + string(JSON VERSION GET ${JSON} "version") + cmate_setg(CMATE_VERSION ${VERSION}) + string(JSON NAMESPACE GET ${JSON} "namespace") + cmate_setg(CMATE_NAMESPACE ${NAMESPACE}) + + string(JSON PKGS GET ${JSON} "packages") + endif() + + cmate_setg(CMATE_PACKAGES "${PKGS}") +endfunction() + +function(cmate_load_link_deps FILE PREFIX) + set(PUBLIC_DEPS "") + set(PRIVATE_DEPS "") + set(LVAR "PUBLIC_DEPS") + + if(EXISTS ${FILE}) + file(READ ${FILE} JSON) + string(JSON LIBS GET ${JSON} "libs") + + foreach(TYPE PUBLIC PRIVATE) + # TODO: add more checks for correct JSON structure + string(TOLOWER ${TYPE} KEY) + cmate_json_get_array(${LIBS} ${KEY} "${TYPE}_DEPS") + endforeach() + endif() + + set(${PREFIX}_PUBLIC_DEPS ${PUBLIC_DEPS} PARENT_SCOPE) + list(LENGTH PUBLIC_DEPS PUBLIC_DEPS_COUNT) + set(${PREFIX}_PUBLIC_DEPS_COUNT ${PUBLIC_DEPS_COUNT} PARENT_SCOPE) + + set(${PREFIX}_PRIVATE_DEPS ${PRIVATE_DEPS} PARENT_SCOPE) + list(LENGTH PRIVATE_DEPS PRIVATE_DEPS_COUNT) + set(${PREFIX}_PRIVATE_DEPS_COUNT ${PRIVATE_DEPS_COUNT} PARENT_SCOPE) + + math(EXPR DEPS_COUNT "${PUBLIC_DEPS_COUNT} + ${PRIVATE_DEPS_COUNT}") + set(${PREFIX}_DEPS_COUNT ${DEPS_COUNT} PARENT_SCOPE) +endfunction() + +############################################################################## +# +# Target common functions +# +############################################################################## +function(cmate_target_link_deps NAME DEPS_FILE VAR) + cmate_load_link_deps(${DEPS_FILE} TGT) + + if(${TGT_DEPS_COUNT} GREATER 0) + set(TDEPS "\ntarget_link_libraries(\n ${NAME}") + + foreach(TYPE PUBLIC PRIVATE) + if(${TGT_${TYPE}_DEPS_COUNT} GREATER 0) + string(APPEND TDEPS "\n ${TYPE}") + + foreach(DEP ${TGT_${TYPE}_DEPS}) + string(APPEND TDEPS "\n ${DEP}") + endforeach() + endif() + endforeach() + + string(APPEND TDEPS "\n)\n") + set(${VAR} ${TDEPS} PARENT_SCOPE) + endif() +endfunction() + +function(cmate_target_name NAME TYPE VAR) + string(TOLOWER "${CMATE_NAMESPACE}_${NAME}_${TYPE}" TBASE) + string(REPLACE "-" "_" TBASE ${TBASE}) + set(${VAR} ${TBASE} PARENT_SCOPE) +endfunction() + +############################################################################## +# +# Library processing functions +# +############################################################################## +function(cmate_configure_lib NAME TBASE INC_BASE SRC_BASE) + string(TOUPPER ${TBASE} VBASE) + + if(${CMATE_DRY_RUN}) + cmate_msg( + "found library ${NAME}" + " (I:${INC_BASE}/${NAME}" + ", S:${SRC_BASE}/${NAME})" + ) + return() + endif() + + list(APPEND CMATE_TARGETS ${TBASE}) + + set(HDIR "${CMATE_ROOT_DIR}/${INC_BASE}/${NAME}") + set(SDIR "${CMATE_ROOT_DIR}/${SRC_BASE}/${NAME}") + set(CM_FILE "${SDIR}/CMakeLists.txt") + set(DEPS_FILE "${SDIR}/cmate.json") + file(GLOB_RECURSE HEADERS "${HDIR}/${CMATE_HEADER_PAT}") + file(GLOB_RECURSE SOURCES "${SDIR}/${CMATE_SOURCE_PAT}") + + string(APPEND CONTENT "add_library(${TBASE})\n") + + if(CMATE_NAMESPACE) + string( + APPEND + CONTENT + "add_library(${CMATE_NAMESPACE}::${NAME} ALIAS ${TBASE})\n" + ) + endif() + + string( + APPEND + CONTENT + " +set(${VBASE}_INC_DIR \"\${PROJECT_SOURCE_DIR}/${INC_BASE}/${NAME}\") +file(GLOB_RECURSE ${VBASE}_HEADERS \${${VBASE}_INC_DIR}/${CMATE_HEADER_PAT}) +list(APPEND ${VBASE}_ALL_SOURCES \${${VBASE}_HEADERS}) + +set(${VBASE}_SRC_DIR \"\${CMAKE_CURRENT_SOURCE_DIR}\") +file(GLOB_RECURSE ${VBASE}_SOURCES \${${VBASE}_SRC_DIR}/${CMATE_SOURCE_PAT}) +list(APPEND ${VBASE}_ALL_SOURCES \${${VBASE}_SOURCES}) + +target_sources( + ${TBASE} + PRIVATE + \${${VBASE}_ALL_SOURCES} +) + +target_include_directories( + ${TBASE} + PUBLIC + $ + $ + PRIVATE + \${CMAKE_CURRENT_SOURCE_DIR} +) +" + ) + + cmate_target_link_deps(${TBASE} ${DEPS_FILE} DEPS) + string(APPEND CONTENT ${DEPS}) + + string( + APPEND + CONTENT + " +set_target_properties( + ${TBASE} + PROPERTIES + VERSION ${CMATE_VERSION} + SOVERSION ${CMATE_VERSION_MAJOR}.${CMATE_VERSION_MINOR} + EXPORT_NAME ${NAME} + OUTPUT_NAME ${CMATE_NAMESPACE}_${NAME} +) +" + ) + + if(${CMATE_DUMP}) + message(${CONTENT}) + endif() + + file(WRITE ${CM_FILE} ${CONTENT}) +endfunction() + +############################################################################## +# +# Binary processing functions +# +############################################################################## +function(cmate_configure_prog TYPE NAME TBASE SRC_BASE) + string(TOUPPER ${TBASE} VBASE) + + if(${CMATE_DRY_RUN}) + cmate_msg("found ${TYPE} ${NAME} (${SRC_BASE}/${NAME})") + return() + endif() + + set(SDIR "${CMATE_ROOT_DIR}/${SRC_BASE}/${NAME}") + set(CM_FILE "${SDIR}/CMakeLists.txt") + set(DEPS_FILE "${SDIR}/cmate.json") + file(GLOB_RECURSE SOURCES "${SDIR}/${CMATE_SOURCE_PAT}") + + string(APPEND CONTENT "add_${TYPE}(${TBASE})\n") + + string( + APPEND + CONTENT + " +set(${VBASE}_SRC_DIR \"\${CMAKE_CURRENT_SOURCE_DIR}\") +file(GLOB_RECURSE ${VBASE}_SOURCES \${${VBASE}_SRC_DIR}/${CMATE_SOURCE_PAT}) +list(APPEND ${VBASE}_ALL_SOURCES \${${VBASE}_SOURCES}) + +target_sources( + ${TBASE} + PRIVATE + \${${VBASE}_ALL_SOURCES} +) + +target_include_directories( + ${TBASE} + PRIVATE + \${CMAKE_CURRENT_SOURCE_DIR} +) +" + ) + + cmate_target_link_deps(${TBASE} ${DEPS_FILE} DEPS) + string(APPEND CONTENT ${DEPS}) + + string( + APPEND + CONTENT + " +set_target_properties( + ${TBASE} + PROPERTIES + OUTPUT_NAME ${NAME} +) +" + ) + + if(${CMATE_DUMP}) + message(${CONTENT}) + endif() + + file(WRITE ${CM_FILE} ${CONTENT}) +endfunction() + +function(cmate_configure_bin NAME TBASE SRC_BASE) + cmate_configure_prog("executable" ${NAME} ${TBASE} ${SRC_BASE}) +endfunction() + +function(cmate_configure_test NAME TBASE SRC_BASE) + cmate_configure_prog("test" ${NAME} ${TBASE} ${SRC_BASE}) +endfunction() + +function(cmate_configure_project_packages VAR) + # CMake style packages + cmate_load_cmake_package_deps("${CMATE_PACKAGES}" "PRJ") + set(CONTENT "") + + if(PRJ_CMAKE_PACKAGES) + string(APPEND CONTENT "\n") + endif() + + foreach(PKG ${PRJ_CMAKE_PACKAGES}) + if(PRJ_CMAKE_${PKG}_COMPS) + string( + APPEND + CONTENT + "find_package( + ${PKG} CONFIG REQUIRED + COMPONENTS +" + ) + + foreach(PC ${PRJ_CMAKE_${PKG}_COMPS}) + string(APPEND CONTENT " ${PC}\n") + endforeach() + + string(APPEND CONTENT ")\n") + else() + string(APPEND CONTENT "find_package(${PKG} CONFIG REQUIRED)\n") + endif() + endforeach() + + # PkgConfig style packages + cmate_load_pkgconfig_package_deps("${CMATE_PACKAGES}" "PRJ") + + if(PRJ_PKGCONFIG_PACKAGES) + string(APPEND CONTENT "find_package(PkgConfig REQUIRED)\n") + endif() + + foreach(PKG ${PRJ_PKGCONFIG_PACKAGES}) + string( + APPEND + CONTENT + "pkg_check_modules(${PKG} REQUIRED IMPORTED_TARGET ${PKG})\n" + ) + endforeach() + + set(${VAR} ${CONTENT} PARENT_SCOPE) +endfunction() + +function(cmate_configure_project TARGETS SUBDIRS) + if(${CMATE_DRY_RUN}) + return() + endif() + + set(CM_FILE "${CMATE_ROOT_DIR}/CMakeLists.txt") + + string( + APPEND + CONTENT + "cmake_minimum_required(VERSION 3.12 FATAL_ERROR) + +project(${CMATE_PROJECT} VERSION 1.0.0 LANGUAGES C CXX) + +include(GNUInstallDirs) + +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) +" + ) + + cmate_configure_project_packages(PKGS) + + if(PKGS) + string(APPEND CONTENT "${PKGS}") + endif() + + # Target subdirs + if(SUBDIRS) + string(APPEND CONTENT "\n") + + foreach(SUBDIR ${SUBDIRS}) + string(APPEND CONTENT "add_subdirectory(${SUBDIR})\n") + endforeach() + endif() + + string( + APPEND + CONTENT + " +install( + TARGETS" + ) + + foreach(TARGET ${TARGETS}) + string(APPEND CONTENT "\n ${TARGET}") + endforeach() + + string( + APPEND + CONTENT + " + EXPORT ${CMATE_PROJECT}-config + RUNTIME DESTINATION \${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION \${CMAKE_INSTALL_LIBDIR} + ARCHIVE DESTINATION \${CMAKE_INSTALL_LIBDIR} +) + +install( + EXPORT ${CMATE_PROJECT}-config + FILE ${CMATE_PROJECT}-config.cmake + NAMESPACE ${CMATE_NAMESPACE}:: + DESTINATION \${CMAKE_INSTALL_LIBDIR}/cmake/${CMATE_PROJECT} +) +" + ) + + if (IS_DIRECTORY "${CMATE_ROOT_DIR}/include") + foreach(LIB ${CMATE_LIBS}) + string( + APPEND + CONTENT + " +install( + DIRECTORY \"\${PROJECT_SOURCE_DIR}/include/${LIB}/\" + DESTINATION \${CMAKE_INSTALL_INCLUDEDIR}/${CMATE_NAMESPACE} +) +" + ) + endforeach() + endif() + + file(WRITE ${CM_FILE} ${CONTENT}) +endfunction() + +############################################################################## +# +# Target processing functions +# +############################################################################## +function(cmate_configure) + # Find libraries (libraries have headers) + file(GLOB LIB_INC_DIRS "${CMATE_ROOT_DIR}/include/*") + set(TARGETS "") + set(LIBS "") + set(SUBDIRS "") + + foreach(LIB_INC_DIR ${LIB_INC_DIRS}) + string(REPLACE "${CMATE_ROOT_DIR}/include/" "" NAME ${LIB_INC_DIR}) + cmate_target_name(${NAME} "lib" "TNAME") + cmate_configure_lib(${NAME} ${TNAME} "include" "src/lib") + list(APPEND TARGETS ${TNAME}) + list(APPEND LIBS ${NAME}) + list(APPEND SUBDIRS "src/lib/${NAME}") + endforeach() + + cmate_setg(CMATE_LIBS "${LIBS}") + + # Binaries and tests + foreach(TYPE bin test) + file(GLOB SRC_DIRS "${CMATE_ROOT_DIR}/src/${TYPE}/*") + + foreach(SRC_DIR ${SRC_DIRS}) + string(REPLACE "${CMATE_ROOT_DIR}/src/${TYPE}/" "" NAME ${SRC_DIR}) + cmate_target_name(${NAME} ${TYPE} "TNAME") + cmake_language( + CALL "cmate_configure_${TYPE}" + ${NAME} ${TNAME} "src/${TYPE}" + ) + + if(NOT "${TYPE}" STREQUAL "test") + list(APPEND TARGETS ${TNAME}) + endif() + + list(APPEND SUBDIRS "src/${TYPE}/${NAME}") + endforeach() + endforeach() + + # Top-level project + cmate_configure_project("${TARGETS}" "${SUBDIRS}") + + cmate_state_file("configured" CONFIGURED) + + if(NOT EXISTS ${CONFIGURED}) + set(BUILD_DIR "${CMATE_ROOT_DIR}/build") + set(STAGE_DIR "${CMATE_ROOT_DIR}/stage") + file(MAKE_DIRECTORY ${BUILD_DIR}) + + set(ARGS "") + + if (EXISTS "${CMATE_CMADE_ENV}") + list(APPEND ARGS "-DCMAKE_PREFIX_PATH=${CMATE_CMADE_ENV}") + endif() + + list(APPEND ARGS "-DCMAKE_INSTALL_PREFIX=${STAGE_DIR}") + list(APPEND ARGS "-DCMAKE_BUILD_TYPE:STRING=Release") + + find_program(CMATE_CCACHE ccache) + + if(CMATE_CCACHE) + list(APPEND ARGS "-DCMAKE_C_COMPILER_LAUNCHER=${CMATE_CCACHE}") + list(APPEND ARGS "-DCMAKE_CXX_COMPILER_LAUNCHER=${CMATE_CCACHE}") + endif() + + find_program(CMATE_NINJA ninja) + + if(CMATE_NINJA) + list(APPEND ARGS "-G" "Ninja") + endif() + + list(APPEND ARGS "-S" "${CMATE_ROOT_DIR}") + list(APPEND ARGS "-B" "${BUILD_DIR}") + + execute_process( + COMMAND + ${CMAKE_COMMAND} + ${ARGS} + WORKING_DIRECTORY "${BUILD_DIR}" + RESULTS_VARIABLE RC + ) + + if(RC) + list(JOIN ARGS " " RUN_CMD) + cmate_die("command failed: ${RUN_CMD}") + endif() + + cmate_set_state("configured") + endif() +endfunction() + +function(cmate_build) + cmate_state_file("configured" CONFIGURED) + + if(NOT EXISTS ${CONFIGURED}) + cmate_die("please configure first") + endif() + + set(BUILD_DIR "${CMATE_ROOT_DIR}/build") + set(STAGE_DIR "${CMATE_ROOT_DIR}/stage") + set(ARGS "") + + list(APPEND ARGS "--build" "${BUILD_DIR}") + list(APPEND ARGS "--parallel") + + execute_process( + COMMAND + ${CMAKE_COMMAND} + ${ARGS} + RESULTS_VARIABLE RC + ) + + if(RC) + list(JOIN ARGS " " RUN_CMD) + cmate_die("command failed: ${RUN_CMD}") + endif() +endfunction() + +function(cmate_stage) + set(BUILD_DIR "${CMATE_ROOT_DIR}/build") + set(ARGS "") + + list(APPEND ARGS "--install" "${BUILD_DIR}") + + execute_process( + COMMAND + ${CMAKE_COMMAND} + ${ARGS} + RESULTS_VARIABLE RC + ) + + if(RC) + list(JOIN ARGS " " RUN_CMD) + cmate_die("command failed: ${RUN_CMD}") + endif() +endfunction() + +function(cmate_clean) + set(BUILD_DIR "${CMATE_ROOT_DIR}/build") + cmate_msg("cleaning: ${BUILD_DIR}") + + if (IS_DIRECTORY ${BUILD_DIR}) + file(REMOVE_RECURSE ${BUILD_DIR}) + endif() + + cmate_clear_states() +endfunction() + +############################################################################## +# +# Configuration functions +# +############################################################################## +function(cmate_check_option OPT OPTS LABEL) + list(FIND OPTS ${OPT} IDX) + + if (IDX LESS 0) + cmate_die("unknown ${LABEL} option: ${OPT}") + endif() +endfunction() + +function(cmate_set_defaults) + get_filename_component(DIR "." ABSOLUTE) + cmate_setg(CMATE_ROOT_DIR ${DIR}) + cmake_path(GET DIR FILENAME PROJECT) + + get_filename_component(DIR ".cmate" ABSOLUTE) + cmate_setg(CMATE_STATE_DIR ${DIR}) + + cmate_setg(CMATE_PROJECT ${PROJECT}) + cmate_setg(CMATE_HEADER_PAT "*.hpp") + cmate_setg(CMATE_SOURCE_PAT "*.[ch]pp") + + cmate_setg(CMATE_CMADE_ENV "${CMATE_ROOT_DIR}/.cmade/env") +endfunction() + +############################################################################## +# +# Argument functions +# +############################################################################## +function(cmate_locate_cmate_arguments) + set(FOUND OFF) + + foreach(POS RANGE ${CMAKE_ARGC}) + string(TOLOWER "${CMAKE_ARGV${POS}}" ARG) + math(EXPR POS "${POS}+1") + + if (ARG MATCHES "${CMATE}$") + # Script args follow us, POS already incremented + set(FOUND ON) + cmate_setg(CMATE_POS ${POS}) + break() + endif() + endforeach() + + if(NOT FOUND) + # Should not happen if script has correct name (see CMATE at top) + cmate_die("parse_argument") + endif() +endfunction() + +function(cmate_parse_arguments) + cmate_locate_cmate_arguments() + set(OPTS_LABEL "generic") + set(OPTS ${CMATE_OPTIONS}) + + while(CMATE_POS LESS ${CMAKE_ARGC}) + if ("${CMAKE_ARGV${CMATE_POS}}" MATCHES "^--?([A-Za-z0-9_-]+)(=(.+))?$") + cmate_check_option(${CMAKE_MATCH_1} "${OPTS}" ${OPTS_LABEL}) + set(OPT "CMATE") + string(APPEND OPT "_${CMAKE_MATCH_1}") + string(REPLACE "-" "_" OPT "${OPT}") + string(TOUPPER ${OPT} OPT) + + if("${CMAKE_MATCH_3}" STREQUAL "") + cmate_setg(${OPT} 1) + else() + cmate_setg(${OPT} "${CMAKE_MATCH_3}") + endif() + elseif("${CMATE_CMD}" STREQUAL "") + set(CMATE_CMD "${CMAKE_ARGV${CMATE_POS}}") + set(OPTS_LABEL ${CMATE_CMD}) + set(OPTS_VAR CMATE_${CMATE_CMD}_OPTIONS) + string(TOUPPER "${OPTS_VAR}" OPTS_VAR) + set(OPTS ${${OPTS_VAR}}) + else() + list(APPEND CMATE_ARGS "${CMAKE_ARGV${CMATE_POS}}") + endif() + + math(EXPR CMATE_POS "${CMATE_POS}+1") + endwhile() + + list(LENGTH CMATE_ARGS CMATE_ARGC) + + cmate_setg(CMATE_CMD "${CMATE_CMD}") + cmate_setg(CMATE_ARGS "${CMATE_ARGS}") + cmate_setg(CMATE_ARGC ${CMATE_ARGC}) + get_filename_component(CMATE_ENV "${CMATE_ENV}" REALPATH) + cmate_setg(CMATE_ENV ${CMATE_ENV}) +endfunction() + +############################################################################## +# +# Command processing +# +############################################################################## +function(cmate_process_cmd) + if (CMATE_CMD STREQUAL "version") + message(${CMATE_VERSION}) + elseif (CMATE_CMD STREQUAL "configure") + cmate_set_version() + cmate_configure() + elseif (CMATE_CMD STREQUAL "build") + cmate_build() + elseif (CMATE_CMD STREQUAL "stage") + cmate_stage() + elseif (CMATE_CMD STREQUAL "clean") + cmate_clean() + elseif (CMATE_CMD STREQUAL "help") + cmate_show_help() + elseif(CMATE_CMD) + cmate_msg("unknown command: ${CMATE_CMD}") + elseif(NOT CMATE_CMD) + cmate_msg("no command") + endif() +endfunction() + +############################################################################## +# +# Main part +# +############################################################################## +if(CMAKE_SCRIPT_MODE_FILE AND NOT CMAKE_PARENT_LIST_FILE) + cmate_set_defaults() + cmate_parse_arguments() + cmate_load_conf("${CMATE_ROOT_DIR}/${CMATE_CONF}") + cmate_process_cmd() +endif() diff --git a/cpp/cmate.json b/cpp/cmate.json new file mode 100644 index 000000000..15f29f6a5 --- /dev/null +++ b/cpp/cmate.json @@ -0,0 +1,11 @@ +{ + "name": "cucumber_gherkin", + "version": "0.1.0", + "namespace": "cucumber", + "packages": { + "cmake": [ + "nlohmann_json", + "cucumber_messages" + ] + } +} diff --git a/cpp/deps.txt b/cpp/deps.txt index b535c7d5a..f96324184 100644 --- a/cpp/deps.txt +++ b/cpp/deps.txt @@ -1,2 +1,2 @@ -https://github.com/nlohmann/json/archive/refs/tags/v3.11.2.zip -DJSON_BuildTests=OFF -https://github.com/cucumber/messages/archive/refs/heads/main.zip --src-dir=cpp +nlohmann/json@v3.11.3 -DJSON_BuildTests=OFF +cucumber/messages@cpp-windows-ci --srcdir=cpp diff --git a/cpp/include/gherkin/app.hpp b/cpp/include/gherkin/cucumber/gherkin/app.hpp similarity index 70% rename from cpp/include/gherkin/app.hpp rename to cpp/include/gherkin/cucumber/gherkin/app.hpp index a9f254936..8eb4ef5d2 100644 --- a/cpp/include/gherkin/app.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/app.hpp @@ -2,19 +2,19 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { class app { public: - using parser = gherkin::parser<>; + using parser = cucumber::gherkin::parser<>; using parser_result = typename parser::result_type; - using callbacks = gherkin::callbacks; + using callbacks = cucumber::gherkin::callbacks; app(); virtual ~app(); diff --git a/cpp/include/gherkin/ast_builder.hpp b/cpp/include/gherkin/cucumber/gherkin/ast_builder.hpp similarity index 91% rename from cpp/include/gherkin/ast_builder.hpp rename to cpp/include/gherkin/cucumber/gherkin/ast_builder.hpp index a63dabeac..a8263025e 100644 --- a/cpp/include/gherkin/ast_builder.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/ast_builder.hpp @@ -7,12 +7,12 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { namespace cms = cucumber::messages; diff --git a/cpp/include/gherkin/ast_node.hpp b/cpp/include/gherkin/cucumber/gherkin/ast_node.hpp similarity index 92% rename from cpp/include/gherkin/ast_node.hpp rename to cpp/include/gherkin/cucumber/gherkin/ast_node.hpp index eb282c30a..8fba04b98 100644 --- a/cpp/include/gherkin/ast_node.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/ast_node.hpp @@ -8,11 +8,11 @@ #include #include -#include -#include -#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { template struct sub_node @@ -120,7 +120,7 @@ class ast_node { using type = std::decay_t; - if constexpr (is_container_v) { + if constexpr (is_specialization_of_v) { using value_type = typename type::value_type; using vector_type = std::vector; @@ -147,7 +147,7 @@ class ast_node { using type = std::decay_t; - if constexpr (is_container_v) { + if constexpr (is_specialization_of_v) { using value_type = typename type::value_type; set_value(rule_type, v); diff --git a/cpp/include/gherkin/builder.hpp b/cpp/include/gherkin/cucumber/gherkin/builder.hpp similarity index 85% rename from cpp/include/gherkin/builder.hpp rename to cpp/include/gherkin/cucumber/gherkin/builder.hpp index cba657c00..ef7de3ca3 100644 --- a/cpp/include/gherkin/builder.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/builder.hpp @@ -3,10 +3,10 @@ #include #include -#include -#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { template struct builder diff --git a/cpp/include/gherkin/cb_types.hpp b/cpp/include/gherkin/cucumber/gherkin/cb_types.hpp similarity index 84% rename from cpp/include/gherkin/cb_types.hpp rename to cpp/include/gherkin/cucumber/gherkin/cb_types.hpp index ec53e2af0..31810d8ce 100644 --- a/cpp/include/gherkin/cb_types.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/cb_types.hpp @@ -7,9 +7,9 @@ #include #include -#include +#include -namespace gherkin { +namespace cucumber::gherkin { namespace cms = cucumber::messages; @@ -22,9 +22,9 @@ struct callbacks { using ast_cb = std::function; - gherkin::source_cb source; + source_cb source; ast_cb ast; - gherkin::pickle_cb pickle; + pickle_cb pickle; error_cb error; }; diff --git a/cpp/include/gherkin/container_helpers.hpp b/cpp/include/gherkin/cucumber/gherkin/container_helpers.hpp similarity index 97% rename from cpp/include/gherkin/container_helpers.hpp rename to cpp/include/gherkin/cucumber/gherkin/container_helpers.hpp index feceb9dd9..0b4867f0b 100644 --- a/cpp/include/gherkin/container_helpers.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/container_helpers.hpp @@ -4,7 +4,7 @@ #include #include -namespace gherkin { +namespace cucumber::gherkin { template struct is_vector : public std::false_type{}; diff --git a/cpp/include/gherkin/demangle.hpp b/cpp/include/gherkin/cucumber/gherkin/demangle.hpp similarity index 91% rename from cpp/include/gherkin/demangle.hpp rename to cpp/include/gherkin/cucumber/gherkin/demangle.hpp index d6f2b2f6c..fe4630801 100644 --- a/cpp/include/gherkin/demangle.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/demangle.hpp @@ -3,7 +3,7 @@ #include #include -namespace gherkin { +namespace cucumber::gherkin { namespace detail { diff --git a/cpp/include/gherkin/dialect.hpp b/cpp/include/gherkin/cucumber/gherkin/dialect.hpp similarity index 91% rename from cpp/include/gherkin/dialect.hpp rename to cpp/include/gherkin/cucumber/gherkin/dialect.hpp index b7d59d4aa..ab0b917f2 100644 --- a/cpp/include/gherkin/dialect.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/dialect.hpp @@ -1,8 +1,8 @@ #pragma once -#include +#include -namespace gherkin { +namespace cucumber::gherkin { using keywords_map = std::unordered_map; using keywords_maps = std::unordered_map; diff --git a/cpp/include/gherkin/exceptions.hpp b/cpp/include/gherkin/cucumber/gherkin/exceptions.hpp similarity index 95% rename from cpp/include/gherkin/exceptions.hpp rename to cpp/include/gherkin/cucumber/gherkin/exceptions.hpp index 770547936..f715dc06a 100644 --- a/cpp/include/gherkin/exceptions.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/exceptions.hpp @@ -5,10 +5,10 @@ #include -#include -#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { namespace cms = cucumber::messages; diff --git a/cpp/include/gherkin/file.hpp b/cpp/include/gherkin/cucumber/gherkin/file.hpp similarity index 71% rename from cpp/include/gherkin/file.hpp rename to cpp/include/gherkin/cucumber/gherkin/file.hpp index e616e0c6c..9cb3ead90 100644 --- a/cpp/include/gherkin/file.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/file.hpp @@ -2,7 +2,7 @@ #include -namespace gherkin { +namespace cucumber::gherkin { struct file { diff --git a/cpp/include/gherkin/id_generator.hpp b/cpp/include/gherkin/cucumber/gherkin/id_generator.hpp similarity index 95% rename from cpp/include/gherkin/id_generator.hpp rename to cpp/include/gherkin/cucumber/gherkin/id_generator.hpp index 5e7941d55..1be437412 100644 --- a/cpp/include/gherkin/id_generator.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/id_generator.hpp @@ -3,7 +3,7 @@ #include #include -namespace gherkin { +namespace cucumber::gherkin { class id_generator_base { diff --git a/cpp/include/gherkin/items.hpp b/cpp/include/gherkin/cucumber/gherkin/items.hpp similarity index 81% rename from cpp/include/gherkin/items.hpp rename to cpp/include/gherkin/cucumber/gherkin/items.hpp index 8b01b5144..ff60ddfa6 100644 --- a/cpp/include/gherkin/items.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/items.hpp @@ -2,7 +2,7 @@ #include -namespace gherkin { +namespace cucumber::gherkin { struct item { diff --git a/cpp/include/gherkin/join_utils.hpp b/cpp/include/gherkin/cucumber/gherkin/join_utils.hpp similarity index 95% rename from cpp/include/gherkin/join_utils.hpp rename to cpp/include/gherkin/cucumber/gherkin/join_utils.hpp index fdc4cca96..1e91cbdd8 100644 --- a/cpp/include/gherkin/join_utils.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/join_utils.hpp @@ -3,9 +3,9 @@ #include #include -#include +#include -namespace gherkin { +namespace cucumber::gherkin { namespace detail { diff --git a/cpp/include/gherkin/keywords.hpp b/cpp/include/gherkin/cucumber/gherkin/keywords.hpp similarity index 77% rename from cpp/include/gherkin/keywords.hpp rename to cpp/include/gherkin/cucumber/gherkin/keywords.hpp index 13a011d32..b3faef207 100644 --- a/cpp/include/gherkin/keywords.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/keywords.hpp @@ -1,6 +1,6 @@ -#include +#include -namespace gherkin { +namespace cucumber::gherkin { const string_views& keywords(const std::string_view& language, const std::string_view& kw); diff --git a/cpp/include/gherkin/line.hpp b/cpp/include/gherkin/cucumber/gherkin/line.hpp similarity index 88% rename from cpp/include/gherkin/line.hpp rename to cpp/include/gherkin/cucumber/gherkin/line.hpp index 727129b63..5d4c6faf5 100644 --- a/cpp/include/gherkin/line.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/line.hpp @@ -2,10 +2,10 @@ #include -#include -#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { class line { diff --git a/cpp/include/gherkin/log.hpp b/cpp/include/gherkin/cucumber/gherkin/log.hpp similarity index 97% rename from cpp/include/gherkin/log.hpp rename to cpp/include/gherkin/cucumber/gherkin/log.hpp index fa0a0670b..9dd8d8984 100644 --- a/cpp/include/gherkin/log.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/log.hpp @@ -4,7 +4,7 @@ #include #include -namespace gherkin { +namespace cucumber::gherkin { template std::string diff --git a/cpp/include/gherkin/msg_types.hpp b/cpp/include/gherkin/cucumber/gherkin/msg_types.hpp similarity index 94% rename from cpp/include/gherkin/msg_types.hpp rename to cpp/include/gherkin/cucumber/gherkin/msg_types.hpp index 0e755ce3b..ac15d3c5e 100644 --- a/cpp/include/gherkin/msg_types.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/msg_types.hpp @@ -4,7 +4,7 @@ #include -namespace gherkin { +namespace cucumber::gherkin { namespace cms = cucumber::messages; diff --git a/cpp/include/gherkin/parse_error.hpp b/cpp/include/gherkin/cucumber/gherkin/parse_error.hpp similarity index 90% rename from cpp/include/gherkin/parse_error.hpp rename to cpp/include/gherkin/cucumber/gherkin/parse_error.hpp index aaddf2605..8f044c9f4 100644 --- a/cpp/include/gherkin/parse_error.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/parse_error.hpp @@ -6,7 +6,7 @@ #include -namespace gherkin { +namespace cucumber::gherkin { using json = nlohmann::json; namespace cms = cucumber::messages; diff --git a/cpp/include/gherkin/parser.hpp b/cpp/include/gherkin/cucumber/gherkin/parser.hpp similarity index 99% rename from cpp/include/gherkin/parser.hpp rename to cpp/include/gherkin/cucumber/gherkin/parser.hpp index 127a96483..340de1a02 100644 --- a/cpp/include/gherkin/parser.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/parser.hpp @@ -1,8 +1,8 @@ // This file is generated. Do not edit! Edit gherkin-cpp-parser.razor instead. -#include -#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { template < typename Builder = ast_builder, diff --git a/cpp/include/gherkin/parser_base.hpp b/cpp/include/gherkin/cucumber/gherkin/parser_base.hpp similarity index 82% rename from cpp/include/gherkin/parser_base.hpp rename to cpp/include/gherkin/cucumber/gherkin/parser_base.hpp index 68afa814a..4f1f65d91 100644 --- a/cpp/include/gherkin/parser_base.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/parser_base.hpp @@ -4,13 +4,13 @@ #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { namespace cms = cucumber::messages; diff --git a/cpp/include/gherkin/parser_context.hpp b/cpp/include/gherkin/cucumber/gherkin/parser_context.hpp similarity index 85% rename from cpp/include/gherkin/parser_context.hpp rename to cpp/include/gherkin/cucumber/gherkin/parser_context.hpp index 2fd0cdb8c..9631f3b36 100644 --- a/cpp/include/gherkin/parser_context.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/parser_context.hpp @@ -1,9 +1,9 @@ -#include -#include -#include -#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { template < typename Builder, diff --git a/cpp/include/gherkin/parser_info.hpp b/cpp/include/gherkin/cucumber/gherkin/parser_info.hpp similarity index 87% rename from cpp/include/gherkin/parser_info.hpp rename to cpp/include/gherkin/cucumber/gherkin/parser_info.hpp index 0ef64b5b5..865b58ead 100644 --- a/cpp/include/gherkin/parser_info.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/parser_info.hpp @@ -3,7 +3,7 @@ #include #include -namespace gherkin { +namespace cucumber::gherkin { using id_generator_func = std::function; diff --git a/cpp/include/gherkin/pickle_compiler.hpp b/cpp/include/gherkin/cucumber/gherkin/pickle_compiler.hpp similarity index 89% rename from cpp/include/gherkin/pickle_compiler.hpp rename to cpp/include/gherkin/cucumber/gherkin/pickle_compiler.hpp index b471ab01c..0f5478923 100644 --- a/cpp/include/gherkin/pickle_compiler.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/pickle_compiler.hpp @@ -2,13 +2,13 @@ #include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { class pickle_compiler { diff --git a/cpp/include/gherkin/pickle_compiler_context.hpp b/cpp/include/gherkin/cucumber/gherkin/pickle_compiler_context.hpp similarity index 54% rename from cpp/include/gherkin/pickle_compiler_context.hpp rename to cpp/include/gherkin/cucumber/gherkin/pickle_compiler_context.hpp index 7f8600107..c1d6c19d9 100644 --- a/cpp/include/gherkin/pickle_compiler_context.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/pickle_compiler_context.hpp @@ -3,11 +3,11 @@ #include #include -#include -#include -#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { struct pickle_compiler_context { @@ -17,7 +17,7 @@ struct pickle_compiler_context id_generator_ptr idp; pickle_cb sink; - gherkin::pickles pickles; + cucumber::gherkin::pickles pickles; std::size_t id_counter_ = 0; }; diff --git a/cpp/include/gherkin/regex.hpp b/cpp/include/gherkin/cucumber/gherkin/regex.hpp similarity index 95% rename from cpp/include/gherkin/regex.hpp rename to cpp/include/gherkin/cucumber/gherkin/regex.hpp index e17c9dd4c..4f0acbc09 100644 --- a/cpp/include/gherkin/regex.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/regex.hpp @@ -3,12 +3,12 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { struct regex_result { diff --git a/cpp/include/gherkin/rule_type.hpp b/cpp/include/gherkin/cucumber/gherkin/rule_type.hpp similarity index 96% rename from cpp/include/gherkin/rule_type.hpp rename to cpp/include/gherkin/cucumber/gherkin/rule_type.hpp index 2a56400c3..2f07b3aad 100644 --- a/cpp/include/gherkin/rule_type.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/rule_type.hpp @@ -4,7 +4,7 @@ #include #include -namespace gherkin { +namespace cucumber::gherkin { enum class rule_type { diff --git a/cpp/include/gherkin/sink.hpp b/cpp/include/gherkin/cucumber/gherkin/sink.hpp similarity index 83% rename from cpp/include/gherkin/sink.hpp rename to cpp/include/gherkin/cucumber/gherkin/sink.hpp index fff214e0e..2eaf68dd8 100644 --- a/cpp/include/gherkin/sink.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/sink.hpp @@ -3,7 +3,7 @@ #include #include -namespace gherkin { +namespace cucumber::gherkin { using json = nlohmann::json; diff --git a/cpp/include/gherkin/token.hpp b/cpp/include/gherkin/cucumber/gherkin/token.hpp similarity index 76% rename from cpp/include/gherkin/token.hpp rename to cpp/include/gherkin/cucumber/gherkin/token.hpp index 99e156776..d96d00788 100644 --- a/cpp/include/gherkin/token.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/token.hpp @@ -9,23 +9,23 @@ #include #include -#include -#include -#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { namespace cms = cucumber::messages; struct token { bool eof = false; - gherkin::line line; + cucumber::gherkin::line line; rule_type matched_type; std::optional matched_keyword; std::optional matched_keyword_type; std::size_t matched_indent = 0; - gherkin::items matched_items; + cucumber::gherkin::items matched_items; std::string matched_text; std::string matched_gherkin_dialect; cms::location location; diff --git a/cpp/include/gherkin/token_formatter_builder.hpp b/cpp/include/gherkin/cucumber/gherkin/token_formatter_builder.hpp similarity index 79% rename from cpp/include/gherkin/token_formatter_builder.hpp rename to cpp/include/gherkin/cucumber/gherkin/token_formatter_builder.hpp index db1c50cf8..209f73f57 100644 --- a/cpp/include/gherkin/token_formatter_builder.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/token_formatter_builder.hpp @@ -2,12 +2,12 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { namespace cms = cucumber::messages; diff --git a/cpp/include/gherkin/token_matcher.hpp b/cpp/include/gherkin/cucumber/gherkin/token_matcher.hpp similarity index 90% rename from cpp/include/gherkin/token_matcher.hpp rename to cpp/include/gherkin/cucumber/gherkin/token_matcher.hpp index 8421d91ec..60ec70051 100644 --- a/cpp/include/gherkin/token_matcher.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/token_matcher.hpp @@ -5,12 +5,12 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { using keyword_types = std::vector; using keyword_types_map = std::unordered_map; @@ -57,7 +57,7 @@ class token_matcher std::optional keyword; std::optional keyword_type; std::optional indent; - gherkin::items items; + cucumber::gherkin::items items; }; void set_token_matched( diff --git a/cpp/include/gherkin/token_scanner.hpp b/cpp/include/gherkin/cucumber/gherkin/token_scanner.hpp similarity index 84% rename from cpp/include/gherkin/token_scanner.hpp rename to cpp/include/gherkin/cucumber/gherkin/token_scanner.hpp index 514f0fa1d..638d66704 100644 --- a/cpp/include/gherkin/token_scanner.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/token_scanner.hpp @@ -3,11 +3,11 @@ #include #include -#include -#include -#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { struct next_line_result { diff --git a/cpp/include/gherkin/cucumber/gherkin/type_traits.hpp b/cpp/include/gherkin/cucumber/gherkin/type_traits.hpp new file mode 100644 index 000000000..3694690e1 --- /dev/null +++ b/cpp/include/gherkin/cucumber/gherkin/type_traits.hpp @@ -0,0 +1,32 @@ +#include + +namespace cucumber::gherkin { + +template < + typename T, + template typename Primary +> +struct is_specialization_of : std::false_type {}; + +template < + template typename Primary, + typename... Args +> +struct is_specialization_of, Primary> : std::true_type {}; + +template < + typename T, + template class Primary +> +using +is_specialization_of_t = is_specialization_of; + +template < + typename T, + template class Primary +> +inline +constexpr bool +is_specialization_of_v = is_specialization_of_t::value; + +} diff --git a/cpp/include/gherkin/types.hpp b/cpp/include/gherkin/cucumber/gherkin/types.hpp similarity index 94% rename from cpp/include/gherkin/types.hpp rename to cpp/include/gherkin/cucumber/gherkin/types.hpp index c6d975fa5..80e821f44 100644 --- a/cpp/include/gherkin/types.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/types.hpp @@ -6,7 +6,7 @@ #include #include -namespace gherkin { +namespace cucumber::gherkin { using strings = std::vector; using strings_map = std::unordered_map; diff --git a/cpp/include/gherkin/utils.hpp b/cpp/include/gherkin/cucumber/gherkin/utils.hpp similarity index 99% rename from cpp/include/gherkin/utils.hpp rename to cpp/include/gherkin/cucumber/gherkin/utils.hpp index a9c53e492..4161b00cf 100644 --- a/cpp/include/gherkin/utils.hpp +++ b/cpp/include/gherkin/cucumber/gherkin/utils.hpp @@ -5,7 +5,7 @@ #include #include -namespace gherkin { +namespace cucumber::gherkin { // utility wrapper to adapt locale-bound facets for wstring/wbuffer convert template diff --git a/cpp/include/gherkin/type_traits.hpp b/cpp/include/gherkin/type_traits.hpp deleted file mode 100644 index 34bf5667d..000000000 --- a/cpp/include/gherkin/type_traits.hpp +++ /dev/null @@ -1,38 +0,0 @@ -#include - -namespace gherkin { - -namespace detail { - -template < - template class Container, - template class Other, - typename T -> -std::is_same, Other> -test_is_container(Other*); - -template < - template class Container, - typename T -> -std::false_type test_is_container(T*); - -} // namespace detail - -template < - template class C, - typename T -> -using is_container = decltype( - detail::test_is_container(static_cast(nullptr)) -); - -template < - template class C, - typename T -> -inline -constexpr bool is_container_v = is_container::value; - -} diff --git a/cpp/src/bin/gherkin-generate-tokens/CMakeLists.txt b/cpp/src/bin/gherkin-generate-tokens/CMakeLists.txt index 8060f2dcb..ecfbe488c 100644 --- a/cpp/src/bin/gherkin-generate-tokens/CMakeLists.txt +++ b/cpp/src/bin/gherkin-generate-tokens/CMakeLists.txt @@ -1,26 +1,29 @@ -add_executable(gherkin-generate-tokens-bin) +add_executable(cucumber_gherkin_generate_tokens_bin) + +set(CUCUMBER_GHERKIN_GENERATE_TOKENS_BIN_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +file(GLOB_RECURSE CUCUMBER_GHERKIN_GENERATE_TOKENS_BIN_SOURCES ${CUCUMBER_GHERKIN_GENERATE_TOKENS_BIN_SRC_DIR}/*.[ch]pp) +list(APPEND CUCUMBER_GHERKIN_GENERATE_TOKENS_BIN_ALL_SOURCES ${CUCUMBER_GHERKIN_GENERATE_TOKENS_BIN_SOURCES}) target_sources( - gherkin-generate-tokens-bin + cucumber_gherkin_generate_tokens_bin PRIVATE - ${CMAKE_SOURCE_DIR}/src/bin/gherkin-generate-tokens/gherkin-generate-tokens.cpp + ${CUCUMBER_GHERKIN_GENERATE_TOKENS_BIN_ALL_SOURCES} ) target_include_directories( - gherkin-generate-tokens-bin + cucumber_gherkin_generate_tokens_bin PRIVATE - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_SOURCE_DIR}/src/bin/gherkin-generate-tokens + ${CMAKE_CURRENT_SOURCE_DIR} ) target_link_libraries( - gherkin-generate-tokens-bin + cucumber_gherkin_generate_tokens_bin PUBLIC - gherkin-cpp + cucumber::gherkin ) set_target_properties( - gherkin-generate-tokens-bin + cucumber_gherkin_generate_tokens_bin PROPERTIES - OUTPUT_NAME gherkin-generate-tokens + OUTPUT_NAME gherkin-generate-tokens ) diff --git a/cpp/src/bin/gherkin-generate-tokens/cmate.json b/cpp/src/bin/gherkin-generate-tokens/cmate.json new file mode 100644 index 000000000..c0bb75fe8 --- /dev/null +++ b/cpp/src/bin/gherkin-generate-tokens/cmate.json @@ -0,0 +1,7 @@ +{ + "libs": { + "public": [ + "cucumber::gherkin" + ] + } +} diff --git a/cpp/src/bin/gherkin-generate-tokens/gherkin-generate-tokens.cpp b/cpp/src/bin/gherkin-generate-tokens/gherkin-generate-tokens.cpp index 3c265c953..f25cd466b 100644 --- a/cpp/src/bin/gherkin-generate-tokens/gherkin-generate-tokens.cpp +++ b/cpp/src/bin/gherkin-generate-tokens/gherkin-generate-tokens.cpp @@ -1,26 +1,26 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include int main(int ac, char** av) { - using builder = gherkin::token_formatter_builder; - using parser = gherkin::parser; + using builder = cucumber::gherkin::token_formatter_builder; + using parser = cucumber::gherkin::parser; parser p; for (std::size_t i = 1; i < ac; ++i) { std::string file(av[i]); - auto data = gherkin::slurp(file); + auto data = cucumber::gherkin::slurp(file); auto ss = p.parse(file, data); - std::cout << gherkin::join("\n", ss); + std::cout << cucumber::gherkin::join("\n", ss); } std::cout << std::endl; diff --git a/cpp/src/bin/gherkin/CMakeLists.txt b/cpp/src/bin/gherkin/CMakeLists.txt index a20251a90..1f8edfc0b 100644 --- a/cpp/src/bin/gherkin/CMakeLists.txt +++ b/cpp/src/bin/gherkin/CMakeLists.txt @@ -1,26 +1,29 @@ -add_executable(gherkin-bin) +add_executable(cucumber_gherkin_bin) + +set(CUCUMBER_GHERKIN_BIN_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +file(GLOB_RECURSE CUCUMBER_GHERKIN_BIN_SOURCES ${CUCUMBER_GHERKIN_BIN_SRC_DIR}/*.[ch]pp) +list(APPEND CUCUMBER_GHERKIN_BIN_ALL_SOURCES ${CUCUMBER_GHERKIN_BIN_SOURCES}) target_sources( - gherkin-bin + cucumber_gherkin_bin PRIVATE - ${CMAKE_SOURCE_DIR}/src/bin/gherkin/gherkin.cpp + ${CUCUMBER_GHERKIN_BIN_ALL_SOURCES} ) target_include_directories( - gherkin-bin + cucumber_gherkin_bin PRIVATE - ${CMAKE_SOURCE_DIR}/ - ${CMAKE_SOURCE_DIR}/src/bin/gherkin + ${CMAKE_CURRENT_SOURCE_DIR} ) target_link_libraries( - gherkin-bin + cucumber_gherkin_bin PUBLIC - gherkin-cpp + cucumber::gherkin ) set_target_properties( - gherkin-bin + cucumber_gherkin_bin PROPERTIES - OUTPUT_NAME gherkin + OUTPUT_NAME gherkin ) diff --git a/cpp/src/bin/gherkin/cmate.json b/cpp/src/bin/gherkin/cmate.json new file mode 100644 index 000000000..c0bb75fe8 --- /dev/null +++ b/cpp/src/bin/gherkin/cmate.json @@ -0,0 +1,7 @@ +{ + "libs": { + "public": [ + "cucumber::gherkin" + ] + } +} diff --git a/cpp/src/bin/gherkin/gherkin.cpp b/cpp/src/bin/gherkin/gherkin.cpp index 57d95d410..c7e92be4b 100644 --- a/cpp/src/bin/gherkin/gherkin.cpp +++ b/cpp/src/bin/gherkin/gherkin.cpp @@ -1,7 +1,7 @@ #include -#include -#include +#include +#include struct options { @@ -72,8 +72,8 @@ int main(int ac, char** av) return opts.exit_code; } - gherkin::app app; - gherkin::app::callbacks cbs{ + cucumber::gherkin::app app; + cucumber::gherkin::app::callbacks cbs{ .source = [&](const auto& m) { print_json_obj("source", m); }, .ast = [&](const auto& m) { print_json_obj("gherkinDocument", m); }, .pickle = [&](const auto& m) { print_json_obj("pickle", m); }, @@ -85,7 +85,7 @@ int main(int ac, char** av) app.include_pickles(opts.include_pickles); for ( ; opts.last_arg < ac; ++opts.last_arg) { - app.parse(gherkin::file{ av[opts.last_arg] }, cbs); + app.parse(cucumber::gherkin::file{ av[opts.last_arg] }, cbs); } return 0; diff --git a/cpp/src/lib/gherkin/CMakeLists.txt b/cpp/src/lib/gherkin/CMakeLists.txt index fda4c0584..b48993629 100644 --- a/cpp/src/lib/gherkin/CMakeLists.txt +++ b/cpp/src/lib/gherkin/CMakeLists.txt @@ -1,38 +1,41 @@ -add_library(gherkin-cpp) -add_library(gherkin::gherkin-cpp ALIAS gherkin-cpp) +add_library(cucumber_gherkin_lib) +add_library(cucumber::gherkin ALIAS cucumber_gherkin_lib) -set(INC_DIR "${CMAKE_SOURCE_DIR}/include") +set(CUCUMBER_GHERKIN_LIB_INC_DIR "${PROJECT_SOURCE_DIR}/include/gherkin") +file(GLOB_RECURSE CUCUMBER_GHERKIN_LIB_HEADERS ${CUCUMBER_GHERKIN_LIB_INC_DIR}/*.hpp) +list(APPEND CUCUMBER_GHERKIN_LIB_ALL_SOURCES ${CUCUMBER_GHERKIN_LIB_HEADERS}) -# We prefer it that way... -file(GLOB_RECURSE GHERKIN_CPP_HEADERS ${INC_DIR}/*.[ch]pp) -file(GLOB_RECURSE GHERKIN_CPP_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/*.[ch]pp) +set(CUCUMBER_GHERKIN_LIB_SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") +file(GLOB_RECURSE CUCUMBER_GHERKIN_LIB_SOURCES ${CUCUMBER_GHERKIN_LIB_SRC_DIR}/*.[ch]pp) +list(APPEND CUCUMBER_GHERKIN_LIB_ALL_SOURCES ${CUCUMBER_GHERKIN_LIB_SOURCES}) target_sources( - gherkin-cpp + cucumber_gherkin_lib PRIVATE - ${GHERKIN_CPP_HEADERS} - ${GHERKIN_CPP_SOURCES} + ${CUCUMBER_GHERKIN_LIB_ALL_SOURCES} ) target_include_directories( - gherkin-cpp + cucumber_gherkin_lib PUBLIC - $ - $ + $ + $ PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ) target_link_libraries( - gherkin-cpp + cucumber_gherkin_lib PUBLIC - cucumber::cucumber-messages nlohmann_json::nlohmann_json + cucumber::messages ) set_target_properties( - gherkin-cpp + cucumber_gherkin_lib PROPERTIES - OUTPUT_NAME gherkin-cpp + VERSION 0.1.0 + SOVERSION 0.1 + EXPORT_NAME gherkin + OUTPUT_NAME cucumber_gherkin ) - diff --git a/cpp/src/lib/gherkin/cmate.json b/cpp/src/lib/gherkin/cmate.json new file mode 100644 index 000000000..d9e9634d7 --- /dev/null +++ b/cpp/src/lib/gherkin/cmate.json @@ -0,0 +1,8 @@ +{ + "libs": { + "public": [ + "nlohmann_json::nlohmann_json", + "cucumber::messages" + ] + } +} diff --git a/cpp/src/lib/gherkin/app.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/app.cpp similarity index 87% rename from cpp/src/lib/gherkin/app.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/app.cpp index 8b351644b..73e018744 100644 --- a/cpp/src/lib/gherkin/app.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/app.cpp @@ -1,9 +1,9 @@ -#include -#include -#include -#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { app::app() : idp_(new_id_generator()), diff --git a/cpp/src/lib/gherkin/ast_builder.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/ast_builder.cpp similarity index 98% rename from cpp/src/lib/gherkin/ast_builder.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/ast_builder.cpp index 84d473af3..da1e281c6 100644 --- a/cpp/src/lib/gherkin/ast_builder.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/ast_builder.cpp @@ -2,12 +2,12 @@ #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { ast_builder::ast_builder() : ast_builder(new_id_generator()) diff --git a/cpp/src/lib/gherkin/ast_node.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/ast_node.cpp similarity index 91% rename from cpp/src/lib/gherkin/ast_node.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/ast_node.cpp index 4511958d8..cd7637c29 100644 --- a/cpp/src/lib/gherkin/ast_node.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/ast_node.cpp @@ -1,6 +1,6 @@ -#include +#include -namespace gherkin { +namespace cucumber::gherkin { ast_node::ast_node(rule_type rule_type) : rule_type_(rule_type) diff --git a/cpp/src/lib/gherkin/demangle.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/demangle.cpp similarity index 85% rename from cpp/src/lib/gherkin/demangle.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/demangle.cpp index c87ff22bc..aed508929 100644 --- a/cpp/src/lib/gherkin/demangle.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/demangle.cpp @@ -3,9 +3,9 @@ #include // gcc and clang… #include -#include +#include -namespace gherkin { +namespace cucumber::gherkin { namespace detail { diff --git a/cpp/src/lib/gherkin/dialect.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/dialect.cpp similarity index 99% rename from cpp/src/lib/gherkin/dialect.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/dialect.cpp index 89abfb5b5..f42014478 100644 --- a/cpp/src/lib/gherkin/dialect.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/dialect.cpp @@ -1,6 +1,6 @@ -#include +#include -namespace gherkin { +namespace cucumber::gherkin { const keywords_maps& all_keywords() diff --git a/cpp/src/lib/gherkin/exceptions.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/exceptions.cpp similarity index 96% rename from cpp/src/lib/gherkin/exceptions.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/exceptions.cpp index 1dced3398..0497842fc 100644 --- a/cpp/src/lib/gherkin/exceptions.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/exceptions.cpp @@ -1,10 +1,10 @@ #include -#include -#include -#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { /////////////////////////////////////////////////////////////////////////////// // diff --git a/cpp/src/lib/gherkin/id_generator.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/id_generator.cpp similarity index 75% rename from cpp/src/lib/gherkin/id_generator.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/id_generator.cpp index 5cdebc069..a83184087 100644 --- a/cpp/src/lib/gherkin/id_generator.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/id_generator.cpp @@ -1,6 +1,6 @@ -#include +#include -namespace gherkin { +namespace cucumber::gherkin { id_generator_base::id_generator_base() {} diff --git a/cpp/src/lib/gherkin/keywords.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/keywords.cpp similarity index 90% rename from cpp/src/lib/gherkin/keywords.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/keywords.cpp index ca5a276ba..8ac66e9df 100644 --- a/cpp/src/lib/gherkin/keywords.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/keywords.cpp @@ -1,7 +1,7 @@ -#include -#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { const string_views& keywords(const std::string_view& language, const std::string_view& kw) diff --git a/cpp/src/lib/gherkin/line.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/line.cpp similarity index 95% rename from cpp/src/lib/gherkin/line.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/line.cpp index c3657373d..c7b92874a 100644 --- a/cpp/src/lib/gherkin/line.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/line.cpp @@ -1,12 +1,12 @@ #include #include -#include -#include -#include -#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { using unescape_pair = std::pair; using unescapes = std::vector; diff --git a/cpp/src/lib/gherkin/parse_error.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/parse_error.cpp similarity index 74% rename from cpp/src/lib/gherkin/parse_error.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/parse_error.cpp index d194f4a1d..70ae6b960 100644 --- a/cpp/src/lib/gherkin/parse_error.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/parse_error.cpp @@ -1,6 +1,6 @@ -#include +#include -namespace gherkin { +namespace cucumber::gherkin { json parse_error::to_json() const diff --git a/cpp/src/lib/gherkin/pickle_compiler.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/pickle_compiler.cpp similarity index 98% rename from cpp/src/lib/gherkin/pickle_compiler.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/pickle_compiler.cpp index 29e1a3a70..ae4457417 100644 --- a/cpp/src/lib/gherkin/pickle_compiler.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/pickle_compiler.cpp @@ -1,8 +1,8 @@ -#include -#include -#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { cms::pickle_step_type to_pickle_step_type(cms::step_keyword_type keyword_type) diff --git a/cpp/src/lib/gherkin/pickle_compiler_context.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/pickle_compiler_context.cpp similarity index 71% rename from cpp/src/lib/gherkin/pickle_compiler_context.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/pickle_compiler_context.cpp index a7455ec70..666673f30 100644 --- a/cpp/src/lib/gherkin/pickle_compiler_context.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/pickle_compiler_context.cpp @@ -1,6 +1,6 @@ -#include +#include -namespace gherkin { +namespace cucumber::gherkin { std::string pickle_compiler_context::next_id() diff --git a/cpp/src/lib/gherkin/regex.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/regex.cpp similarity index 93% rename from cpp/src/lib/gherkin/regex.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/regex.cpp index a71a371c1..27dc83c09 100644 --- a/cpp/src/lib/gherkin/regex.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/regex.cpp @@ -1,6 +1,6 @@ -#include +#include -namespace gherkin { +namespace cucumber::gherkin { void split(const std::string& re, const std::string& expr, strings& list) diff --git a/cpp/src/lib/gherkin/rule_type.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/rule_type.cpp similarity index 96% rename from cpp/src/lib/gherkin/rule_type.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/rule_type.cpp index 4b7233414..54b488c6e 100644 --- a/cpp/src/lib/gherkin/rule_type.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/rule_type.cpp @@ -1,8 +1,8 @@ #include -#include +#include -namespace gherkin { +namespace cucumber::gherkin { std::string_view to_string(rule_type r) diff --git a/cpp/src/lib/gherkin/token.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/token.cpp similarity index 70% rename from cpp/src/lib/gherkin/token.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/token.cpp index 8efd28137..1191600e9 100644 --- a/cpp/src/lib/gherkin/token.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/token.cpp @@ -1,6 +1,6 @@ -#include +#include -namespace gherkin { +namespace cucumber::gherkin { bool token::is_eof() const diff --git a/cpp/src/lib/gherkin/token_formatter_builder.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/token_formatter_builder.cpp similarity index 91% rename from cpp/src/lib/gherkin/token_formatter_builder.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/token_formatter_builder.cpp index 179762809..609190738 100644 --- a/cpp/src/lib/gherkin/token_formatter_builder.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/token_formatter_builder.cpp @@ -1,9 +1,9 @@ #include -#include -#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { token_formatter_builder::token_formatter_builder(id_generator_ptr idp) : idp_(idp) diff --git a/cpp/src/lib/gherkin/token_matcher.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/token_matcher.cpp similarity index 95% rename from cpp/src/lib/gherkin/token_matcher.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/token_matcher.cpp index 9d8928e3f..24b614c6d 100644 --- a/cpp/src/lib/gherkin/token_matcher.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/token_matcher.cpp @@ -1,11 +1,11 @@ -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { static const std::regex language_re{ "^\\s*#\\s*language\\s*:\\s*([a-zA-Z\\-_]+)\\s*$" @@ -211,7 +211,7 @@ bool token_matcher::match_step_line(token& token) { string_views kws = { "given", "when", "then", "and", "but" }; - auto keywords = gherkin::keywords(dialect_name_, kws); + auto keywords = cucumber::gherkin::keywords(dialect_name_, kws); for (const auto& keyword : keywords) { if (!token.line.startswith(keyword)) { @@ -319,7 +319,7 @@ token_matcher::set_token_matched( const string_views& token_matcher::keywords(std::string_view kw) const -{ return gherkin::keywords(dialect_name_, kw); } +{ return cucumber::gherkin::keywords(dialect_name_, kw); } cucumber::messages::step_keyword_type token_matcher::keyword_type(std::string_view keyword) const diff --git a/cpp/src/lib/gherkin/token_scanner.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/token_scanner.cpp similarity index 86% rename from cpp/src/lib/gherkin/token_scanner.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/token_scanner.cpp index de90b59c8..78b49af91 100644 --- a/cpp/src/lib/gherkin/token_scanner.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/token_scanner.cpp @@ -2,10 +2,10 @@ #include #include -#include -#include +#include +#include -namespace gherkin { +namespace cucumber::gherkin { token_scanner::token_scanner() {} @@ -28,7 +28,7 @@ token_scanner::read() return token{ .eof = r.eof, - .line = gherkin::line(r.text, line_), + .line = cucumber::gherkin::line(r.text, line_), .location = { .line = line_ } diff --git a/cpp/src/lib/gherkin/utils.cpp b/cpp/src/lib/gherkin/cucumber/gherkin/utils.cpp similarity index 92% rename from cpp/src/lib/gherkin/utils.cpp rename to cpp/src/lib/gherkin/cucumber/gherkin/utils.cpp index 3b827a2c5..a4cf8c1d3 100644 --- a/cpp/src/lib/gherkin/utils.cpp +++ b/cpp/src/lib/gherkin/cucumber/gherkin/utils.cpp @@ -5,9 +5,9 @@ #include #include -#include +#include -namespace gherkin { +namespace cucumber::gherkin { std::string slurp(const std::string& path) From d0564b89dd2acbf3eb42e6360d12fc9c31a61ab2 Mon Sep 17 00:00:00 2001 From: Remy Chibois Date: Thu, 4 Jan 2024 17:46:13 +0100 Subject: [PATCH 2/4] chore: using new cmate tool --- .github/workflows/test-cpp.yml | 28 +- cpp/.gitignore | 2 +- cpp/CMakeLists.txt | 2 +- cpp/cmake/cmade | 544 --------- cpp/cmake/cmate | 1025 ++++++++++++----- cpp/deps.txt | 2 +- cpp/{cmate.json => project.json} | 0 .../{cmate.json => link.json} | 0 cpp/src/bin/gherkin/{cmate.json => link.json} | 0 cpp/src/lib/gherkin/{cmate.json => link.json} | 0 10 files changed, 761 insertions(+), 842 deletions(-) delete mode 100755 cpp/cmake/cmade rename cpp/{cmate.json => project.json} (100%) rename cpp/src/bin/gherkin-generate-tokens/{cmate.json => link.json} (100%) rename cpp/src/bin/gherkin/{cmate.json => link.json} (100%) rename cpp/src/lib/gherkin/{cmate.json => link.json} (100%) diff --git a/.github/workflows/test-cpp.yml b/.github/workflows/test-cpp.yml index 30118c1b7..ea84c8f33 100644 --- a/.github/workflows/test-cpp.yml +++ b/.github/workflows/test-cpp.yml @@ -20,23 +20,23 @@ on: jobs: test-cpp: - runs-on: ubuntu-latest - + strategy: + matrix: + os: + #- ubuntu-20.04 + #- ubuntu-22.04 + #- windows-2019 + - windows-2022 + runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v4 - - - name: install cmake and libraries + - name: install dependencies + working-directory: cpp run: | - sudo apt-get update - sudo apt-get install ninja-build cmake - sudo apt-get install nlohmann-json3-dev - ninja --version - cmake --version - gcc --version + cmake -P cmake/cmate update - name: configure and build - env: - NPROCS: 1 - run: | - make acceptance working-directory: cpp + run: | + cmake -P cmake/cmate configure + cmake -P cmake/cmate build diff --git a/cpp/.gitignore b/cpp/.gitignore index 8418e80fc..8bba1c4da 100644 --- a/cpp/.gitignore +++ b/cpp/.gitignore @@ -2,7 +2,7 @@ ext/ build/ acceptance/ stage/ -.cmade/ +.cenv/ .cmate/ .built .configured diff --git a/cpp/CMakeLists.txt b/cpp/CMakeLists.txt index 2c00dcb6b..6b07b3b2a 100644 --- a/cpp/CMakeLists.txt +++ b/cpp/CMakeLists.txt @@ -1,6 +1,6 @@ cmake_minimum_required(VERSION 3.12 FATAL_ERROR) -project(cucumber_gherkin VERSION 1.0.0 LANGUAGES C CXX) +project(cucumber_gherkin VERSION 0.1.0 LANGUAGES C CXX) include(GNUInstallDirs) diff --git a/cpp/cmake/cmade b/cpp/cmake/cmade deleted file mode 100755 index bf62d492b..000000000 --- a/cpp/cmake/cmade +++ /dev/null @@ -1,544 +0,0 @@ -#!/usr/bin/env -S cmake -P -# -*- CMake -*- - -set(CMADE "cmade") -set(CMADE_DEPSFILE "deps.txt") -set(CMADE_VERSION "X.Y.Z") -list( - APPEND - CMADE_VARS - "CMADE_GIT_HOST=GH" - "CMADE_GH=https://github.com" - "CMADE_GL=https://gitlab.com" - "CMADE_BB=https://bitbucket.org" -) -list( - APPEND - CMADE_OPTIONS - "verbose" - "simulate" - "no-cache" -) - - -############################################################################## -# -# Utility functions -# -############################################################################## -function(cmade_show_help) - message("\ -CMake Dependency Installer v${CMADE_VERSION} - -usage: ${CMADE} [OPTIONS] COMMAND - -Options: - --verbose Verbose operation - --simulate Echo commands instead of running them - --no-cache Ignore/erase existing repositories - -Commands: - install Install dependencies from ${CMADE_DEPSFILE} - clean Clean local environment - help Display this information -") -endfunction() - -function(cmade_die MSG) - message(FATAL_ERROR "CMade: error: ${MSG}") -endfunction() - -function(cmade_msg MSG) - message("CMade: ${MSG}") -endfunction() - -function(cmade_info MSG) - if(CMADE_VERBOSE) - cmade_msg(${MSG}) - endif() -endfunction() - -function(cmade_setg VAR VAL) - set(${VAR} "${VAL}" CACHE INTERNAL "${VAR}") -endfunction() - -function(cmade_run_prog) - cmake_parse_arguments(RUN "" "DIR" "CMD" ${ARGN}) - - if(CMADE_SIMULATE) - list(PREPEND RUN_CMD "echo") - endif() - - execute_process( - COMMAND ${RUN_CMD} - WORKING_DIRECTORY "${RUN_DIR}" - RESULTS_VARIABLE RC - ) - - if(RC) - list(JOIN ARGV " " RUN_CMD) - cmade_die("command failed: ${RUN_CMD}") - endif() -endfunction() - -function(cmade_download URL FILE) - if(CMADE_SIMULATE) - cmade_msg("download ${URL} to ${FILE}") - else() - file(DOWNLOAD ${URL} ${FILE} STATUS ST) - endif() - - list(GET ST 0 RC) - - if(RC) - cmade_die("download of ${URL} failed: ${ST}") - endif() -endfunction() - -function(cmade_unique_dir PATH VAR) - file(GLOB PATHS "${PATH}/*") - - foreach(PATH ${PATHS}) - if(IS_DIRECTORY ${PATH}) - list(APPEND ALL_DIRS ${PATH}) - endif() - endforeach() - - list(LENGTH ALL_DIRS DIRS) - - if(DIRS EQUAL 0) - cmade_die("no directories found in ${PATH}") - elseif(DIRS GREATER 1) - cmade_die("multiple directories found ${PATH}") - endif() - - list(GET ALL_DIRS 0 DIR) - set(${VAR} ${DIR} PARENT_SCOPE) -endfunction() - -function(cmade_set_cache_dir NAME) - string(REPLACE "/" "_" DIR ${NAME}) - set(DIR "${CMADE_CACHE}/${DIR}") - cmade_setg(CMADE_CACHE_DIR ${DIR}) - cmade_setg(CMADE_SOURCE_DIR "${DIR}/sources") - cmade_setg(CMADE_BUILD_DIR "${DIR}/build") - cmade_setg(CMADE_STATE_DIR "${DIR}/state") - - if(CMADE_NO_CACHE) - file(REMOVE_RECURSE "${DIR}") - endif() -endfunction() - -function(cmade_state_file STATE VAR) - set(${VAR} "${CMADE_STATE_DIR}/.${STATE}" PARENT_SCOPE) -endfunction() - -function(cmade_set_state STATE) - file(MAKE_DIRECTORY ${CMADE_STATE_DIR}) - cmade_state_file(${STATE} FILE) - file(TOUCH ${FILE}) -endfunction() - -function(cmade_fetch_repo HOST REPO REF) - if(HOST MATCHES "^\\$\\{(.+)\\}$") - # Dereference variable - set(HOST ${${CMAKE_MATCH_1}}) - endif() - - if(HOST STREQUAL "GH") - set(HOST "https://github.com") - elseif(TYPE STREQUAL "GL") - set(HOST "https://gitlab.com") - endif() - - set(URL "${HOST}/${REPO}.git") - - set(GIT_ARGS "clone") - list( - APPEND GIT_ARGS - -c advice.detachedHead=false - --depth 1 - ) - - if(REF) - list(APPEND GIT_ARGS --branch "${REF}") - endif() - - cmade_set_cache_dir(${REPO}) - cmade_state_file("fetched" FETCHED) - - if(NOT IS_DIRECTORY ${CMADE_SOURCE_DIR} OR NOT EXISTS ${FETCHED}) - # Whatever the reason, we're (re-)fetching - file(REMOVE_RECURSE ${CMADE_SOURCE_DIR}) - cmade_info("cloning ${URL} in ${CMADE_SOURCE_DIR}") - cmade_run_prog(CMD git ${GIT_ARGS} ${URL} ${CMADE_SOURCE_DIR}) - cmade_set_state("fetched") - endif() -endfunction() - -function(cmade_fetch_url URL) - string(MD5 HASH ${URL}) - - if(URL MATCHES "/([^/]+)$") - set(FILE ${CMAKE_MATCH_1}) - else() - cmade_die("can't find filename from URL: ${URL}") - endif() - - cmade_set_cache_dir(${HASH}) - cmade_state_file("fetched" FETCHED) - cmade_state_file("extracted" EXTRACTED) - set(CFILE "${CMADE_CACHE_DIR}/${FILE}") - - if(NOT EXISTS ${CFILE}) - cmade_info("downloading ${URL} in ${CDIR}") - cmade_download(${URL} ${CFILE}) - cmade_set_state("fetched") - endif() - - if(NOT IS_DIRECTORY ${CMADE_SOURCE_DIR} OR NOT EXISTS ${EXTRACTED}) - file(REMOVE_RECURSE ${CMADE_SOURCE_DIR}) - cmade_info("extracting ${FILE}") - file( - ARCHIVE_EXTRACT - INPUT ${CFILE} - DESTINATION ${CMADE_SOURCE_DIR} - ) - cmade_set_state("extracted") - endif() - - cmade_unique_dir(${CMADE_SOURCE_DIR} SDIR) - cmade_setg(CMADE_SOURCE_DIR ${SDIR}) -endfunction() - -############################################################################## -# -# Dependency installation functions -# -############################################################################## -function(cmade_build_cmake_dep) - cmade_state_file("configured" CONFIGURED) - cmade_state_file("built" BUILT) - cmade_state_file("installed" INSTALLED) - - cmade_msg("building with: ${ARGV}") - - if(NOT EXISTS ${CONFIGURED}) - set(ARGS "") - - find_program(CMADE_CCACHE ccache) - - if(CMATE_CCACHE) - list(APPEND ARGS "-DCMAKE_C_COMPILER_LAUNCHER=${CMADE_CCACHE}") - list(APPEND ARGS "-DCMAKE_CXX_COMPILER_LAUNCHER=${CMADE_CCACHE}") - endif() - - find_program(CMADE_NINJA ninja) - - if(CMADE_NINJA) - list(APPEND ARGS "-G" "Ninja") - endif() - - cmade_run_prog( - CMD - ${CMAKE_COMMAND} - -DCMAKE_PREFIX_PATH=${CMADE_ENV} - -DCMAKE_INSTALL_PREFIX=${CMADE_ENV} - -DCMAKE_BUILD_TYPE:STRING=Release - ${ARGS} - -S ${CMADE_SOURCE_DIR} -B ${CMADE_BUILD_DIR} - ${ARGV} - ) - cmade_set_state("configured") - endif() - if(NOT EXISTS ${BUILT}) - cmade_run_prog(CMD ${CMAKE_COMMAND} --build ${CMADE_BUILD_DIR} --parallel) - cmade_set_state("built") - endif() - if(NOT EXISTS ${INSTALLED}) - cmade_run_prog(CMD ${CMAKE_COMMAND} --install ${CMADE_BUILD_DIR}) - cmade_set_state("installed") - endif() -endfunction() - -function(cmade_build_meson_dep) - cmade_state_file("configured" CONFIGURED) - cmade_state_file("installed" INSTALLED) - file(MAKE_DIRECTORY ${CMADE_BUILD_DIR}) - - if(NOT EXISTS ${CONFIGURED}) - cmade_run_prog( - DIR ${CMADE_BUILD_DIR} - CMD - meson - --prefix=${CMADE_ENV} - --pkg-config-path=${CMADE_ENV} - --cmake-prefix-path=${CMADE_ENV} - ${ARGV} - . ${SRCDIR} - ) - cmade_set_state("configured") - endif() - if(NOT EXISTS ${INSTALLED}) - cmade_run_prog(meson install) - cmade_set_state("installed") - endif() -endfunction() - -function(cmade_build_autotools_dep) - cmade_state_file("configured" CONFIGURED) - cmade_state_file("installed" INSTALLED) - file(MAKE_DIRECTORY ${CMADE_BUILD_DIR}) - - if(NOT EXISTS ${CONFIGURED}) - cmade_run_prog( - DIR ${CMADE_BUILD_DIR} - CMD - ${CMADE_SOURCE_DIR}/configure - --prefix=${CMADE_ENV} - ${ARGV} - ) - cmade_set_state("configured") - endif() - if(NOT EXISTS ${INSTALLED}) - cmade_run_prog( - DIR ${CMADE_BUILD_DIR} - CMD make install - ) - cmade_set_state("installed") - endif() -endfunction() - -function(cmade_build_makefile_dep) - cmade_state_file("built" BUILT) - cmade_state_file("installed" INSTALLED) - file(MAKE_DIRECTORY ${CMADE_BUILD_DIR}) - - if(NOT EXISTS ${BUILT}) - cmade_run_prog( - DIR ${CMADE_SOURCE_DIR} - CMD make - ) - cmade_set_state("built") - endif() - if(NOT EXISTS ${INSTALLED}) - cmade_run_prog( - DIR ${CMADE_SOURCE_DIR} - CMD make prefix=${CMADE_ENV} install - ) - cmade_set_state("installed") - endif() -endfunction() - -function(cmade_build_dep ARGS) - set(OPT_PROC ON) - string(REGEX MATCHALL "[^ \"']+|\"([^\"]*)\"|'([^']*)'" ARGS "${ARGS}") - - foreach(ARG ${ARGS}) - if(OPT_PROC AND ARG MATCHES "^--") - if(ARG STREQUAL "--") - set(OPT_PROC OFF) - elseif(ARG MATCHES "^--srcdir=(.+)") - cmade_setg( - CMADE_SOURCE_DIR - "${CMADE_SOURCE_DIR}/${CMAKE_MATCH_1}" - ) - endif() - else() - list(APPEND CONF_ARGS ${ARG}) - endif() - endforeach() - - if(NOT IS_DIRECTORY "${CMADE_SOURCE_DIR}") - cmade_die("invalid source directory: ${CMADE_SOURCE_DIR}") - endif() - - if(EXISTS "${CMADE_SOURCE_DIR}/CMakeLists.txt") - cmade_build_cmake_dep(${CONF_ARGS}) - elseif(EXISTS "${CMADE_SOURCE_DIR}/meson.build") - cmade_build_meson_dep(${CONF_ARGS}) - elseif(EXISTS "${CMADE_SOURCE_DIR}/configure") - cmade_build_autotools_dep(${CONF_ARGS}) - elseif(EXISTS "${CMADE_SOURCE_DIR}/Makefile") - cmade_build_makefile_dep(${CONF_ARGS}) - else() - cmade_die("don't know how to build in ${CMADE_SOURCE_DIR}") - endif() -endfunction() - -function(cmade_install_repo HOST REPO TAG ARGS) - cmade_fetch_repo(${HOST} ${REPO} "${TAG}") - cmade_build_dep("${ARGS}") -endfunction() - -function(cmade_install_url URL ARGS) - cmade_fetch_url(${URL}) - cmade_build_dep("${ARGS}") -endfunction() - -function(cmade_install) - if(NOT EXISTS ${CMADE_DEPSFILE}) - cmade_msg("no dependencies") - return() - endif() - - file(STRINGS ${CMADE_DEPSFILE} DEPS) - - foreach(SPEC ${DEPS}) - if(SPEC MATCHES "^#") - # Skip comments - continue() - elseif(SPEC MATCHES "^([A-Za-z0-9_-]+)=(.+)$") - # Variable assignment - cmade_setg("CMADE_${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}") - elseif(SPEC MATCHES "^([a-z]+://[^ ]+)([ ](.+))?$") - # URL - set(URL ${CMAKE_MATCH_1}) - set(ARGS "${CMAKE_MATCH_3}") - cmade_msg("checking ${URL}") - cmade_install_url(${URL} "${ARGS}") - elseif(SPEC MATCHES "^(([^: ]+):)?([^@ ]+)(@([^ ]+))?([ ](.+))?$") - # GitHub/GitLab style project short ref - if(CMAKE_MATCH_2) - if(CMADE_${CMAKE_MATCH_2}) - set(HOST ${CMADE_${CMAKE_MATCH_2}}) - else() - cmade_die("unknown id: ${CMAKE_MATCH_2}") - endif() - else() - set(HOST ${CMADE_${CMADE_GIT_HOST}}) - endif() - - set(REPO ${CMAKE_MATCH_3}) - set(TAG ${CMAKE_MATCH_5}) - set(ARGS "${CMAKE_MATCH_7}") - cmade_msg("checking ${REPO}") - cmade_install_repo(${HOST} ${REPO} "${TAG}" "${ARGS}") - else() - cmade_die("invalid dependency line: ${SPEC}") - endif() - endforeach() -endfunction() - -############################################################################## -# -# Environment cleaning functions -# -############################################################################## -function(cmade_clean) - cmade_msg("cleaning: ${CMADE_ROOT}") - - if (IS_DIRECTORY ${CMADE_ROOT}) - file(REMOVE_RECURSE ${CMADE_ROOT}) - endif() -endfunction() - -############################################################################## -# -# Argument functions -# -############################################################################## -function(cmade_locate_cmade_arguments) - set(FOUND OFF) - - foreach(POS RANGE ${CMAKE_ARGC}) - string(TOLOWER "${CMAKE_ARGV${POS}}" ARG) - math(EXPR POS "${POS}+1") - - if (ARG MATCHES "${CMADE}$") - # Script args follow us, POS already incremented - set(FOUND ON) - cmade_setg(CMADE_POS ${POS}) - break() - endif() - endforeach() - - if(NOT FOUND) - # Should not happen if script has correct name (see CMADE at top) - cmade_die("parse_argument") - endif() -endfunction() - -function(cmade_parse_arguments) - cmade_locate_cmade_arguments() - - while(CMADE_POS LESS ${CMAKE_ARGC}) - if ("${CMAKE_ARGV${CMADE_POS}}" MATCHES "--?([A-Za-z0-9_-]+)") - list(FIND CMADE_OPTIONS ${CMAKE_MATCH_1} OPT) - - if (OPT LESS 0) - cmade_die("unknown option: ${CMAKE_MATCH_1}") - else() - string(TOUPPER "CMADE_${CMAKE_MATCH_1}" OPT) - string(REPLACE "-" "_" OPT "${OPT}") - cmade_setg(${OPT} 1) - endif() - else() - list(APPEND CMADE_ARGS "${CMAKE_ARGV${CMADE_POS}}") - endif() - - math(EXPR CMADE_POS "${CMADE_POS}+1") - endwhile() - - list(LENGTH CMADE_ARGS CMADE_ARGC) - - if (CMADE_ARGC GREATER 0) - list(POP_FRONT CMADE_ARGS CMADE_CMD) - cmade_setg(CMADE_CMD "${CMADE_CMD}") - endif() - - cmade_setg(CMADE_ARGS "${CMADE_ARGS}") - get_filename_component(CMADE_ENV "${CMADE_ENV}" REALPATH) - cmade_setg(CMADE_ENV ${CMADE_ENV}) -endfunction() - -############################################################################## -# -# Default variables -# -############################################################################## -function(cmade_set_vars) - get_filename_component(DIR ".cmade" ABSOLUTE) - cmade_setg(CMADE_ROOT ${DIR}) - get_filename_component(DIR "cache" ABSOLUTE BASE_DIR ${CMADE_ROOT}) - cmade_setg(CMADE_CACHE ${DIR}) - get_filename_component(DIR "env" ABSOLUTE BASE_DIR ${CMADE_ROOT}) - cmade_setg(CMADE_ENV ${DIR}) - - foreach(VDEF ${CMADE_VARS}) - if(VDEF MATCHES "^CMADE_([^=]+)=(.*)$") - cmade_info("default: ${CMAKE_MATCH_1}=${CMAKE_MATCH_2}") - cmade_setg("CMADE_${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}") - endif() - endforeach() -endfunction() - -############################################################################## -# -# Command processing -# -############################################################################## -function(cmade_process_cmd) - if (CMADE_CMD STREQUAL "version") - message(${CMADE_VERSION}) - elseif (CMADE_CMD STREQUAL "install") - cmade_install() - elseif (CMADE_CMD STREQUAL "clean") - cmade_clean() - elseif (CMADE_CMD STREQUAL "help") - cmade_show_help() - elseif(CMADE_CMD) - cmade_msg("unknown command: ${CMADE_CMD}") - elseif(NOT CMADE_CMD) - cmade_msg("no command") - endif() -endfunction() - -############################################################################## -# -# Main part -# -############################################################################## -cmade_parse_arguments() -cmade_set_vars() -cmade_process_cmd() diff --git a/cpp/cmake/cmate b/cpp/cmake/cmate index 8ff0d4de7..69dff0f13 100755 --- a/cpp/cmake/cmate +++ b/cpp/cmake/cmate @@ -3,137 +3,22 @@ set(CMATE "cmate") set(CMATE_VER "X.Y.Z") -set(CMATE_CONF "cmate.json") -cmake_policy(SET CMP0057 NEW) -list( - APPEND - CMATE_CMDS - "configure" - "build" - "stage" - "clean" -) -list( - APPEND - CMATE_OPTIONS - "verbose" -) -list( - APPEND - CMATE_CONFIGURE_OPTIONS - "dry-run" - "dump" - "namespace" - "version" - "version-file" - "source-pat" - "header-pat" -) -############################################################################## -# -# Help messages -# -############################################################################## -set(CMATE_HELP_HEADER "CMake Automatic TargEts v${CMATE_VER}") - -# Generic help -set( - CMATE_HELP - " -Usage: cmate [OPTIONS] COMMAND - -Options: - --verbose Verbose operation - -Commands: - configure Scans and configures targets - build - clean - stage - help Display this information - -See 'cmate help ' to read about a specific subcommand." -) - -# Configure help -set( - CMATE_CONFIGURE_HELP - " -Usage: cmate configure [OPTIONS] - -Configure local project - -Options: - --dry-run Don't touch anything - --dump Dump generated CMakeLists.txt - --namespace=NS CMake package namespace - --version=SEMVER CMake package version - --version-file=FILE CMake package version from FILE - --version-file=FILE CMake package version from FILE - --source-pat=PATTERN CMate targets source file glob pattern - (default: \$CACHE{CMATE_SOURCE_PAT}) - --header-pat=PATTERN CMate targets header file glob pattern - (default: \$CACHE{CMATE_HEADER_PAT})" -) - -# Build help -set( - CMATE_BUILD_HELP - " -Usage: cmate build - -Build local project" -) - -# Stage help -set( - CMATE_STAGE_HELP - " -Usage: cmate stage - -Stage local project" -) - -# Clean help -set( - CMATE_CLEAN_HELP - " -Usage: cmate clean - -Clean local project" -) -############################################################################## -# -# Targets -# -############################################################################## set(CMATE_TARGETS "") +set(CMATE_CMDS "") +set(CMATE_DEPSFILE "deps.txt") +set(CMATE_PRJFILE "project.json") +set(CMATE_LINKFILE "link.json") +set(CMATE_GIT_HOST "GH") +set(CMATE_GH "https://github.com") +set(CMATE_GL "https://gitlab.com") +set(CMATE_BB "https://bitbucket.org") +cmake_policy(SET CMP0057 NEW) -############################################################################## +############################################################################### # -# Utility functions +# Content of cmate/utilities.cmake # -############################################################################## -function(cmate_show_help) - set(HVAR "CMATE") - if(CMATE_ARGC GREATER 0) - list(GET CMATE_ARGS 0 HCMD) - - if(${HCMD} IN_LIST CMATE_CMDS) - string(TOUPPER "${HCMD}" HCMD) - string(APPEND HVAR "_${HCMD}") - else() - cmate_die("no such command: ${HCMD}") - endif() - endif() - - string(APPEND HVAR "_HELP") - string(CONFIGURE ${${HVAR}} HELP) - - message("${CMATE_HELP_HEADER}") - message(${HELP}) -endfunction() - +############################################################################### function(cmate_die MSG) message(FATAL_ERROR "CMate: error: ${MSG}") endfunction() @@ -205,17 +90,17 @@ endfunction() function(cmate_set_version) cmate_load_version() - if("${CMATE_VERSION}" STREQUAL "") + if("${CMATE_PROJECT_VERSION}" STREQUAL "") cmate_warn("using default version: 0.1.0") - cmate_setg(CMATE_VERSION "0.1.0") + cmate_setg(CMATE_PROJECT_VERSION "0.1.0") endif() - if("${CMATE_VERSION}" MATCHES "^([^\\.]+)\\.([^\\.]+)\\.([^\\.]+)$") - cmate_setg(CMATE_VERSION_MAJOR ${CMAKE_MATCH_1}) - cmate_setg(CMATE_VERSION_MINOR ${CMAKE_MATCH_2}) - cmate_setg(CMATE_VERSION_PATCH ${CMAKE_MATCH_3}) + if("${CMATE_PROJECT_VERSION}" MATCHES "^([^\\.]+)\\.([^\\.]+)\\.([^\\.]+)$") + cmate_setg(CMATE_PROJECT_VERSION_MAJOR ${CMAKE_MATCH_1}) + cmate_setg(CMATE_PROJECT_VERSION_MINOR ${CMAKE_MATCH_2}) + cmate_setg(CMATE_PROJECT_VERSION_PATCH ${CMAKE_MATCH_3}) else() - cmate_die("unable to parse version: ${CMATE_VERSION}") + cmate_die("unable to parse version: ${CMATE_PROJECT_VERSION}") endif() endfunction() @@ -245,6 +130,162 @@ function(cmate_json_get_array JSON KEY VAR) set(${VAR} ${ITEMS} PARENT_SCOPE) endfunction() +function(cmate_load_conf FILE) + set(PKGS "") + + if(EXISTS ${FILE}) + file(READ ${FILE} JSON) + + string(JSON PROJECT GET ${JSON} "name") + cmate_setg(CMATE_PROJECT_NAME ${PROJECT}) + string(JSON VERSION GET ${JSON} "version") + cmate_setg(CMATE_PROJECT_VERSION "${VERSION}") + cmate_set_version() + string(JSON NAMESPACE GET ${JSON} "namespace") + cmate_setg(CMATE_PROJECT_NAMESPACE ${NAMESPACE}) + + string(JSON PKGS GET ${JSON} "packages") + endif() + + cmate_setg(CMATE_PACKAGES "${PKGS}") +endfunction() + +function(cmate_run_prog) + cmake_parse_arguments(RUN "" "DIR" "CMD" ${ARGN}) + + if(CMATE_SIMULATE) + list(PREPEND RUN_CMD "echo") + endif() + + execute_process( + COMMAND ${RUN_CMD} + WORKING_DIRECTORY "${RUN_DIR}" + RESULTS_VARIABLE RC + ) + + if(RC) + list(JOIN ARGV " " RUN_CMD) + cmate_die("command failed: ${RUN_CMD}") + endif() +endfunction() + +function(cmate_unique_dir PATH VAR) + file(GLOB PATHS "${PATH}/*") + + foreach(PATH ${PATHS}) + if(IS_DIRECTORY ${PATH}) + list(APPEND ALL_DIRS ${PATH}) + endif() + endforeach() + + list(LENGTH ALL_DIRS DIRS) + + if(DIRS EQUAL 0) + cmate_die("no directories found in ${PATH}") + elseif(DIRS GREATER 1) + cmate_die("multiple directories found ${PATH}") + endif() + + list(GET ALL_DIRS 0 DIR) + set(${VAR} ${DIR} PARENT_SCOPE) +endfunction() + +function(cmate_download URL FILE) + if(CMATE_SIMULATE) + cmate_msg("download ${URL} to ${FILE}") + else() + file(DOWNLOAD ${URL} ${FILE} STATUS ST) + endif() + + list(GET ST 0 RC) + + if(RC) + cmate_die("download of ${URL} failed: ${ST}") + endif() +endfunction() +############################################################################### +# +# Content of cmate/args.cmake +# +############################################################################### +function(cmate_check_option OPT OPTS LABEL) + list(FIND OPTS ${OPT} IDX) + + if (IDX LESS 0) + cmate_die("unknown ${LABEL} option: ${OPT}") + endif() +endfunction() + +function(cmate_locate_cmate_arguments) + set(FOUND OFF) + + foreach(POS RANGE ${CMAKE_ARGC}) + string(TOLOWER "${CMAKE_ARGV${POS}}" ARG) + math(EXPR POS "${POS}+1") + + if (ARG MATCHES "${CMATE}$") + # Script args follow us, POS already incremented + set(FOUND ON) + cmate_setg(CMATE_POS ${POS}) + break() + endif() + endforeach() + + if(NOT FOUND) + # Should not happen if script has correct name (see CMATE at top) + cmate_die("parse_argument") + endif() +endfunction() + +function(cmate_parse_arguments) + cmate_locate_cmate_arguments() + set(OPTS_LABEL "generic") + set(OPTS ${CMATE_OPTIONS}) + + while(CMATE_POS LESS ${CMAKE_ARGC}) + if ("${CMAKE_ARGV${CMATE_POS}}" MATCHES "^--?([A-Za-z0-9_-]+)(=(.+))?$") + #cmate_check_option(${CMAKE_MATCH_1} "${OPTS}" ${OPTS_LABEL}) + set(OPT "CMATE") + + if(CMATE_CMD) + string(APPEND OPT "_${CMATE_CMD}") + endif() + + string(APPEND OPT "_${CMAKE_MATCH_1}") + string(REPLACE "-" "_" OPT "${OPT}") + string(TOUPPER ${OPT} OPT) + + if("${CMAKE_MATCH_3}" STREQUAL "") + cmate_setg(${OPT} 1) + else() + cmate_setg(${OPT} "${CMAKE_MATCH_3}") + endif() + elseif("${CMATE_CMD}" STREQUAL "") + set(CMATE_CMD "${CMAKE_ARGV${CMATE_POS}}") + set(OPTS_LABEL ${CMATE_CMD}) + set(OPTS_VAR CMATE_${CMATE_CMD}_OPTIONS) + string(TOUPPER "${OPTS_VAR}" OPTS_VAR) + set(OPTS ${${OPTS_VAR}}) + else() + list(APPEND CMATE_ARGS "${CMAKE_ARGV${CMATE_POS}}") + endif() + + math(EXPR CMATE_POS "${CMATE_POS}+1") + endwhile() + + list(LENGTH CMATE_ARGS CMATE_ARGC) + + cmate_setg(CMATE_CMD "${CMATE_CMD}") + cmate_setg(CMATE_ARGS "${CMATE_ARGS}") + cmate_setg(CMATE_ARGC ${CMATE_ARGC}) + get_filename_component(CMATE_ENV "${CMATE_ENV}" REALPATH) + cmate_setg(CMATE_ENV ${CMATE_ENV}) +endfunction() +############################################################################### +# +# Content of cmate/target_deps.cmake +# +############################################################################### function(cmate_load_cmake_package_deps JSON PREFIX) cmate_json_get_array("${JSON}" "cmake" "PKGS") set(PACKAGES "") @@ -278,25 +319,6 @@ function(cmate_load_pkgconfig_package_deps JSON PREFIX) set("${PREFIX}_PKGCONFIG_PACKAGES" ${PKGS} PARENT_SCOPE) endfunction() -function(cmate_load_conf FILE) - set(PKGS "") - - if(EXISTS ${FILE}) - file(READ ${FILE} JSON) - - string(JSON PROJECT GET ${JSON} "name") - cmate_setg(CMATE_PROJECT ${PROJECT}) - string(JSON VERSION GET ${JSON} "version") - cmate_setg(CMATE_VERSION ${VERSION}) - string(JSON NAMESPACE GET ${JSON} "namespace") - cmate_setg(CMATE_NAMESPACE ${NAMESPACE}) - - string(JSON PKGS GET ${JSON} "packages") - endif() - - cmate_setg(CMATE_PACKAGES "${PKGS}") -endfunction() - function(cmate_load_link_deps FILE PREFIX) set(PUBLIC_DEPS "") set(PRIVATE_DEPS "") @@ -325,13 +347,8 @@ function(cmate_load_link_deps FILE PREFIX) set(${PREFIX}_DEPS_COUNT ${DEPS_COUNT} PARENT_SCOPE) endfunction() -############################################################################## -# -# Target common functions -# -############################################################################## -function(cmate_target_link_deps NAME DEPS_FILE VAR) - cmate_load_link_deps(${DEPS_FILE} TGT) +function(cmate_target_link_deps NAME FILE VAR) + cmate_load_link_deps(${FILE} TGT) if(${TGT_DEPS_COUNT} GREATER 0) set(TDEPS "\ntarget_link_libraries(\n ${NAME}") @@ -352,16 +369,144 @@ function(cmate_target_link_deps NAME DEPS_FILE VAR) endfunction() function(cmate_target_name NAME TYPE VAR) - string(TOLOWER "${CMATE_NAMESPACE}_${NAME}_${TYPE}" TBASE) + string(TOLOWER "${CMATE_PROJECT_NAMESPACE}_${NAME}_${TYPE}" TBASE) string(REPLACE "-" "_" TBASE ${TBASE}) set(${VAR} ${TBASE} PARENT_SCOPE) endfunction() +############################################################################### +# +# Content of cmate/deps.cmake +# +############################################################################### +function(cmate_dep_set_cache_dir NAME) + string(REPLACE "/" "_" DIR ${NAME}) + set(DIR "${CMATE_DEPS_DIR}/${DIR}") + cmate_setg(CMATE_DEP_CACHE_DIR ${DIR}) + cmate_setg(CMATE_DEP_SOURCE_DIR "${DIR}/sources") + cmate_setg(CMATE_DEP_BUILD_DIR "${DIR}/build") + cmate_setg(CMATE_DEP_STATE_DIR "${DIR}/state") +endfunction() + +function(cmate_dep_state_file STATE VAR) + set(${VAR} "${CMATE_DEP_STATE_DIR}/.${STATE}" PARENT_SCOPE) +endfunction() + +function(cmate_dep_set_state STATE) + file(MAKE_DIRECTORY ${CMATE_DEP_STATE_DIR}) + cmate_dep_state_file(${STATE} FILE) + file(TOUCH ${FILE}) +endfunction() + +function(cmate_dep_get_repo HOST REPO REF) + if(HOST MATCHES "^\\$\\{(.+)\\}$") + # Dereference variable + set(HOST ${${CMAKE_MATCH_1}}) + endif() + + if(HOST STREQUAL "GH") + set(HOST "https://github.com") + elseif(TYPE STREQUAL "GL") + set(HOST "https://gitlab.com") + endif() + + set(URL "${HOST}/${REPO}.git") + + set(GIT_ARGS "clone") + list( + APPEND GIT_ARGS + -c advice.detachedHead=false + --depth 1 + ) + + if(REF) + list(APPEND GIT_ARGS --branch "${REF}") + endif() + + cmate_dep_set_cache_dir(${REPO}) + cmate_dep_state_file("fetched" FETCHED) + + if(NOT IS_DIRECTORY ${CMATE_DEP_SOURCE_DIR} OR NOT EXISTS ${FETCHED}) + # Whatever the reason, we're (re-)fetching + file(REMOVE_RECURSE ${CMATE_DEP_SOURCE_DIR}) + cmate_info("cloning ${URL} in ${CMATE_DEP_SOURCE_DIR}") + cmate_run_prog(CMD git ${GIT_ARGS} ${URL} ${CMATE_DEP_SOURCE_DIR}) + cmate_dep_set_state("fetched") + endif() +endfunction() + +function(cmate_dep_get_url URL) + string(MD5 HASH ${URL}) + + if(URL MATCHES "/([^/]+)$") + set(FILE ${CMAKE_MATCH_1}) + else() + cmate_die("can't find filename from URL: ${URL}") + endif() + + cmate_dep_set_cache_dir(${HASH}) + cmate_dep_state_file("fetched" FETCHED) + cmate_dep_state_file("extracted" EXTRACTED) + set(CFILE "${CMATE_DEP_CACHE_DIR}/${FILE}") + + if(NOT EXISTS ${CFILE}) + cmate_info("downloading ${URL} in ${CDIR}") + cmate_download(${URL} ${CFILE}) + cmate_set_state("fetched") + endif() + + if(NOT IS_DIRECTORY ${CMATE_DEP_SOURCE_DIR} OR NOT EXISTS ${EXTRACTED}) + file(REMOVE_RECURSE ${CMATE_DEP_SOURCE_DIR}) + cmate_info("extracting ${FILE}") + file( + ARCHIVE_EXTRACT + INPUT ${CFILE} + DESTINATION ${CMATE_DEP_SOURCE_DIR} + ) + cmate_dep_set_state("extracted") + endif() + + cmate_unique_dir(${CMATE_DEP_SOURCE_DIR} SDIR) + cmate_setg(CMATE_DEP_SOURCE_DIR ${SDIR}) +endfunction() +############################################################################### +# +# Content of cmate/commands/configure.cmake +# +############################################################################### +list(APPEND CMATE_CMDS "configure") +list( + APPEND + CMATE_CONFIGURE_OPTIONS + "dry-run" + "dump" + "namespace" + "version" + "version-file" + "source-pat" + "header-pat" +) +set(CMATE_CONFIGURE_SHORT_HELP "Configure local project") +set( + CMATE_CONFIGURE_HELP + " +Usage: cmate configure [OPTIONS] + +${CMATE_CONFIGURE_SHORT_HELP} + +Options: + --toolchain=FILE CMake toolchain file + --dry-run Don't touch anything + --dump Dump generated CMakeLists.txt + --namespace=NS CMake package namespace + --version=SEMVER CMake package version + --version-file=FILE CMake package version from FILE + --version-file=FILE CMake package version from FILE + --source-pat=PATTERN CMate targets source file glob pattern + (default: \$CACHE{CMATE_SOURCE_PAT}) + --header-pat=PATTERN CMate targets header file glob pattern + (default: \$CACHE{CMATE_HEADER_PAT})" +) -############################################################################## -# -# Library processing functions -# -############################################################################## function(cmate_configure_lib NAME TBASE INC_BASE SRC_BASE) string(TOUPPER ${TBASE} VBASE) @@ -379,17 +524,18 @@ function(cmate_configure_lib NAME TBASE INC_BASE SRC_BASE) set(HDIR "${CMATE_ROOT_DIR}/${INC_BASE}/${NAME}") set(SDIR "${CMATE_ROOT_DIR}/${SRC_BASE}/${NAME}") set(CM_FILE "${SDIR}/CMakeLists.txt") - set(DEPS_FILE "${SDIR}/cmate.json") + set(LINK_FILE "${SDIR}/${CMATE_LINKFILE}") + file(GLOB_RECURSE HEADERS "${HDIR}/${CMATE_HEADER_PAT}") file(GLOB_RECURSE SOURCES "${SDIR}/${CMATE_SOURCE_PAT}") string(APPEND CONTENT "add_library(${TBASE})\n") - if(CMATE_NAMESPACE) + if(CMATE_PROJECT_NAMESPACE) string( APPEND CONTENT - "add_library(${CMATE_NAMESPACE}::${NAME} ALIAS ${TBASE})\n" + "add_library(${CMATE_PROJECT_NAMESPACE}::${NAME} ALIAS ${TBASE})\n" ) endif() @@ -415,14 +561,14 @@ target_include_directories( ${TBASE} PUBLIC $ - $ + $ PRIVATE \${CMAKE_CURRENT_SOURCE_DIR} ) " ) - cmate_target_link_deps(${TBASE} ${DEPS_FILE} DEPS) + cmate_target_link_deps(${TBASE} ${LINK_FILE} DEPS) string(APPEND CONTENT ${DEPS}) string( @@ -432,10 +578,10 @@ target_include_directories( set_target_properties( ${TBASE} PROPERTIES - VERSION ${CMATE_VERSION} - SOVERSION ${CMATE_VERSION_MAJOR}.${CMATE_VERSION_MINOR} + VERSION ${CMATE_PROJECT_VERSION} + SOVERSION ${CMATE_PROJECT_VERSION_MAJOR}.${CMATE_PROJECT_VERSION_MINOR} EXPORT_NAME ${NAME} - OUTPUT_NAME ${CMATE_NAMESPACE}_${NAME} + OUTPUT_NAME ${CMATE_PROJECT_NAMESPACE}_${NAME} ) " ) @@ -447,11 +593,6 @@ set_target_properties( file(WRITE ${CM_FILE} ${CONTENT}) endfunction() -############################################################################## -# -# Binary processing functions -# -############################################################################## function(cmate_configure_prog TYPE NAME TBASE SRC_BASE) string(TOUPPER ${TBASE} VBASE) @@ -462,7 +603,7 @@ function(cmate_configure_prog TYPE NAME TBASE SRC_BASE) set(SDIR "${CMATE_ROOT_DIR}/${SRC_BASE}/${NAME}") set(CM_FILE "${SDIR}/CMakeLists.txt") - set(DEPS_FILE "${SDIR}/cmate.json") + set(LINK_FILE "${SDIR}/${CMATE_LINKFILE}") file(GLOB_RECURSE SOURCES "${SDIR}/${CMATE_SOURCE_PAT}") string(APPEND CONTENT "add_${TYPE}(${TBASE})\n") @@ -489,7 +630,7 @@ target_include_directories( " ) - cmate_target_link_deps(${TBASE} ${DEPS_FILE} DEPS) + cmate_target_link_deps(${TBASE} ${LINK_FILE} DEPS) string(APPEND CONTENT ${DEPS}) string( @@ -579,7 +720,7 @@ function(cmate_configure_project TARGETS SUBDIRS) CONTENT "cmake_minimum_required(VERSION 3.12 FATAL_ERROR) -project(${CMATE_PROJECT} VERSION 1.0.0 LANGUAGES C CXX) +project(${CMATE_PROJECT_NAME} VERSION ${CMATE_PROJECT_VERSION} LANGUAGES C CXX) include(GNUInstallDirs) @@ -621,17 +762,17 @@ install( APPEND CONTENT " - EXPORT ${CMATE_PROJECT}-config + EXPORT ${CMATE_PROJECT_NAME}-config RUNTIME DESTINATION \${CMAKE_INSTALL_BINDIR} LIBRARY DESTINATION \${CMAKE_INSTALL_LIBDIR} ARCHIVE DESTINATION \${CMAKE_INSTALL_LIBDIR} ) install( - EXPORT ${CMATE_PROJECT}-config - FILE ${CMATE_PROJECT}-config.cmake - NAMESPACE ${CMATE_NAMESPACE}:: - DESTINATION \${CMAKE_INSTALL_LIBDIR}/cmake/${CMATE_PROJECT} + EXPORT ${CMATE_PROJECT_NAME}-config + FILE ${CMATE_PROJECT_NAME}-config.cmake + NAMESPACE ${CMATE_PROJECT_NAMESPACE}:: + DESTINATION \${CMAKE_INSTALL_LIBDIR}/cmake/${CMATE_PROJECT_NAME} ) " ) @@ -644,7 +785,7 @@ install( " install( DIRECTORY \"\${PROJECT_SOURCE_DIR}/include/${LIB}/\" - DESTINATION \${CMAKE_INSTALL_INCLUDEDIR}/${CMATE_NAMESPACE} + DESTINATION \${CMAKE_INSTALL_INCLUDEDIR}/${CMATE_PROJECT_NAMESPACE} ) " ) @@ -654,11 +795,6 @@ install( file(WRITE ${CM_FILE} ${CONTENT}) endfunction() -############################################################################## -# -# Target processing functions -# -############################################################################## function(cmate_configure) # Find libraries (libraries have headers) file(GLOB LIB_INC_DIRS "${CMATE_ROOT_DIR}/include/*") @@ -709,8 +845,8 @@ function(cmate_configure) set(ARGS "") - if (EXISTS "${CMATE_CMADE_ENV}") - list(APPEND ARGS "-DCMAKE_PREFIX_PATH=${CMATE_CMADE_ENV}") + if (EXISTS "${CMATE_ENV_DIR}") + list(APPEND ARGS "-DCMAKE_PREFIX_PATH=${CMATE_ENV_DIR}") endif() list(APPEND ARGS "-DCMAKE_INSTALL_PREFIX=${STAGE_DIR}") @@ -729,6 +865,10 @@ function(cmate_configure) list(APPEND ARGS "-G" "Ninja") endif() + if(CMATE_TOOLCHAIN) + list(APPEND ARGS "--toolchain" "${CMATE_TOOLCHAIN}") + endif() + list(APPEND ARGS "-S" "${CMATE_ROOT_DIR}") list(APPEND ARGS "-B" "${BUILD_DIR}") @@ -748,6 +888,39 @@ function(cmate_configure) cmate_set_state("configured") endif() endfunction() +############################################################################### +# +# Content of cmate/commands/reconfigure.cmake +# +############################################################################### +list(APPEND CMATE_CMDS "reconfigure") +set(CMATE_RECONFIGURE_SHORT_HELP "Clean + configure") +set( + CMATE_RECONFIGURE_HELP + " +Usage: cmate reconfigure + +${CMATE_RECONFIGURE_SHORT_HELP}" +) + +function(cmate_reconfigure) + cmate_clean() + cmate_configure() +endfunction() +############################################################################### +# +# Content of cmate/commands/build.cmake +# +############################################################################### +list(APPEND CMATE_CMDS "build") +set(CMATE_BUILD_SHORT_HELP "Build local project") +set( + CMATE_BUILD_HELP + " +Usage: cmate build + +${CMATE_BUILD_SHORT_HELP}" +) function(cmate_build) cmate_state_file("configured" CONFIGURED) @@ -775,6 +948,39 @@ function(cmate_build) cmate_die("command failed: ${RUN_CMD}") endif() endfunction() +############################################################################### +# +# Content of cmate/commands/rebuild.cmake +# +############################################################################### +list(APPEND CMATE_CMDS "rebuild") +set(CMATE_REBUILD_SHORT_HELP "Reconfigure + build") +set( + CMATE_REBUILD_HELP + " +Usage: cmate rebuild + +${CMATE_REBUILD_SHORT_HELP}" +) + +function(cmate_rebuild) + cmate_reconfigure() + cmate_build() +endfunction() +############################################################################### +# +# Content of cmate/commands/stage.cmake +# +############################################################################### +list(APPEND CMATE_CMDS "stage") +set(CMATE_STAGE_SHORT_HELP "Stage local project") +set( + CMATE_STAGE_HELP + " +Usage: cmate stage + +${CMATE_STAGE_SHORT_HELP}" +) function(cmate_stage) set(BUILD_DIR "${CMATE_ROOT_DIR}/build") @@ -794,110 +1000,372 @@ function(cmate_stage) cmate_die("command failed: ${RUN_CMD}") endif() endfunction() +############################################################################### +# +# Content of cmate/commands/clean.cmake +# +############################################################################### +list(APPEND CMATE_CMDS "clean") +set(CMATE_CLEAN_SHORT_HELP "Clean local project") +set( + CMATE_CLEAN_HELP + " +Usage: cmate clean + +${CMATE_CLEAN_SHORT_HELP} + +Options: + --purge Remove everything: cenv, dependencies, ..." +) function(cmate_clean) - set(BUILD_DIR "${CMATE_ROOT_DIR}/build") - cmate_msg("cleaning: ${BUILD_DIR}") + set(DIRS "BUILD" "STAGE" "STATE") - if (IS_DIRECTORY ${BUILD_DIR}) - file(REMOVE_RECURSE ${BUILD_DIR}) + if(${CMATE_CLEAN_PURGE}) + list(APPEND DIRS "ENV" "DEPS") endif() - cmate_clear_states() -endfunction() + foreach(DIR ${DIRS}) + set(DVAR "CMATE_${DIR}_DIR") -############################################################################## + if (IS_DIRECTORY ${${DVAR}}) + cmate_msg("cleaning: ${${DVAR}}") + file(REMOVE_RECURSE ${${DVAR}}) + endif() + endforeach() +endfunction() +############################################################################### # -# Configuration functions +# Content of cmate/commands/update.cmake # -############################################################################## -function(cmate_check_option OPT OPTS LABEL) - list(FIND OPTS ${OPT} IDX) +############################################################################### +list(APPEND CMATE_CMDS "update") +set(CMATE_UPDATE_SHORT_HELP "Update dependencies listed in deps.txt") +set( + CMATE_UPDATE_HELP + " +Usage: cmate update - if (IDX LESS 0) - cmate_die("unknown ${LABEL} option: ${OPT}") +${CMATE_UPDATE_SHORT_HELP}" +) + +function(cmate_update_cmake_dep) + cmate_dep_state_file("configured" CONFIGURED) + cmate_dep_state_file("built" BUILT) + cmate_dep_state_file("installed" INSTALLED) + + if(NOT EXISTS ${CONFIGURED}) + cmate_msg("building with: ${ARGV}") + + set(ARGS "") + + find_program(CMATE_CCACHE ccache) + + if(CMATE_CCACHE) + list(APPEND ARGS "-DCMAKE_C_COMPILER_LAUNCHER=${CMATE_CCACHE}") + list(APPEND ARGS "-DCMAKE_CXX_COMPILER_LAUNCHER=${CMATE_CCACHE}") + endif() + + find_program(CMATE_NINJA ninja) + + if(CMATE_NINJA) + list(APPEND ARGS "-G" "Ninja") + endif() + + cmate_run_prog( + CMD + ${CMAKE_COMMAND} + -DCMAKE_PREFIX_PATH=${CMATE_ENV_DIR} + -DCMAKE_INSTALL_PREFIX=${CMATE_ENV_DIR} + -DCMAKE_BUILD_TYPE:STRING=Release + ${ARGS} + -S ${CMATE_DEP_SOURCE_DIR} -B ${CMATE_DEP_BUILD_DIR} + ${ARGV} + ) + cmate_dep_set_state("configured") + endif() + if(NOT EXISTS ${BUILT}) + cmate_run_prog( + CMD + ${CMAKE_COMMAND} + --build ${CMATE_DEP_BUILD_DIR} + --parallel + ) + cmate_dep_set_state("built") + endif() + if(NOT EXISTS ${INSTALLED}) + cmate_run_prog(CMD ${CMAKE_COMMAND} --install ${CMATE_DEP_BUILD_DIR}) + cmate_dep_set_state("installed") endif() endfunction() -function(cmate_set_defaults) - get_filename_component(DIR "." ABSOLUTE) - cmate_setg(CMATE_ROOT_DIR ${DIR}) - cmake_path(GET DIR FILENAME PROJECT) +function(cmate_update_meson_dep) + cmate_dep_state_file("configured" CONFIGURED) + cmate_dep_state_file("installed" INSTALLED) + file(MAKE_DIRECTORY ${CMATE_DEP_BUILD_DIR}) - get_filename_component(DIR ".cmate" ABSOLUTE) - cmate_setg(CMATE_STATE_DIR ${DIR}) + if(NOT EXISTS ${CONFIGURED}) + cmate_run_prog( + DIR ${CMATE_DEP_BUILD_DIR} + CMD + meson + --prefix=${CMATE_ENV_DIR} + --pkg-config-path=${CMATE_ENV_DIR} + --cmake-prefix-path=${CMATE_ENV_DIR} + ${ARGV} + . ${SRCDIR} + ) + cmate_dep_set_state("configured") + endif() + if(NOT EXISTS ${INSTALLED}) + cmate_run_prog(meson install) + cmate_dep_set_state("installed") + endif() +endfunction() - cmate_setg(CMATE_PROJECT ${PROJECT}) - cmate_setg(CMATE_HEADER_PAT "*.hpp") - cmate_setg(CMATE_SOURCE_PAT "*.[ch]pp") +function(cmate_update_autotools_dep) + cmate_dep_state_file("configured" CONFIGURED) + cmate_dep_state_file("installed" INSTALLED) + file(MAKE_DIRECTORY ${CMATE_DEP_BUILD_DIR}) - cmate_setg(CMATE_CMADE_ENV "${CMATE_ROOT_DIR}/.cmade/env") + if(NOT EXISTS ${CONFIGURED}) + cmate_run_prog( + DIR ${CMATE_DEP_BUILD_DIR} + CMD + ${CMATE_DEP_SOURCE_DIR}/configure + --prefix=${CMATE_ENV_DIR} + ${ARGV} + ) + cmate_dep_set_state("configured") + endif() + if(NOT EXISTS ${INSTALLED}) + cmate_run_prog( + DIR ${CMATE_DEP_BUILD_DIR} + CMD make install + ) + cmate_dep_set_state("installed") + endif() endfunction() -############################################################################## -# -# Argument functions -# -############################################################################## -function(cmate_locate_cmate_arguments) - set(FOUND OFF) +function(cmate_update_makefile_dep) + cmate_dep_state_file("built" BUILT) + cmate_dep_state_file("installed" INSTALLED) + file(MAKE_DIRECTORY ${CMATE_DEP_BUILD_DIR}) - foreach(POS RANGE ${CMAKE_ARGC}) - string(TOLOWER "${CMAKE_ARGV${POS}}" ARG) - math(EXPR POS "${POS}+1") + if(NOT EXISTS ${BUILT}) + cmate_run_prog( + DIR ${CMATE_DEP_SOURCE_DIR} + CMD make + ) + cmate_dep_set_state("built") + endif() + if(NOT EXISTS ${INSTALLED}) + cmate_run_prog( + DIR ${CMATE_DEP_SOURCE_DIR} + CMD make prefix=${CMATE_ENV_DIR} install + ) + cmate_dep_set_state("installed") + endif() +endfunction() - if (ARG MATCHES "${CMATE}$") - # Script args follow us, POS already incremented - set(FOUND ON) - cmate_setg(CMATE_POS ${POS}) - break() +function(cmate_update_dep ARGS) + set(OPT_PROC ON) + string(REGEX MATCHALL "[^ \"']+|\"([^\"]*)\"|'([^']*)'" ARGS "${ARGS}") + + foreach(ARG ${ARGS}) + if(OPT_PROC AND ARG MATCHES "^--") + if(ARG STREQUAL "--") + set(OPT_PROC OFF) + elseif(ARG MATCHES "^--srcdir=(.+)") + cmate_setg( + CMATE_DEP_SOURCE_DIR + "${CMATE_DEP_SOURCE_DIR}/${CMAKE_MATCH_1}" + ) + endif() + else() + list(APPEND CONF_ARGS ${ARG}) endif() endforeach() - if(NOT FOUND) - # Should not happen if script has correct name (see CMATE at top) - cmate_die("parse_argument") + if(NOT IS_DIRECTORY "${CMATE_DEP_SOURCE_DIR}") + cmate_die("invalid source directory: ${CMATE_DEP_SOURCE_DIR}") + endif() + + if(EXISTS "${CMATE_DEP_SOURCE_DIR}/CMakeLists.txt") + cmate_update_cmake_dep(${CONF_ARGS}) + elseif(EXISTS "${CMATE_DEP_SOURCE_DIR}/meson.build") + cmate_update_meson_dep(${CONF_ARGS}) + elseif(EXISTS "${CMATE_DEP_SOURCE_DIR}/configure") + cmate_update_autotools_dep(${CONF_ARGS}) + elseif(EXISTS "${CMATE_DEP_SOURCE_DIR}/Makefile") + cmate_update_makefile_dep(${CONF_ARGS}) + else() + cmate_die("don't know how to build in ${CMATE_DEP_SOURCE_DIR}") endif() endfunction() -function(cmate_parse_arguments) - cmate_locate_cmate_arguments() - set(OPTS_LABEL "generic") - set(OPTS ${CMATE_OPTIONS}) +function(cmate_update_repo HOST REPO TAG ARGS) + cmate_dep_get_repo(${HOST} ${REPO} "${TAG}") + cmate_update_dep("${ARGS}") +endfunction() - while(CMATE_POS LESS ${CMAKE_ARGC}) - if ("${CMAKE_ARGV${CMATE_POS}}" MATCHES "^--?([A-Za-z0-9_-]+)(=(.+))?$") - cmate_check_option(${CMAKE_MATCH_1} "${OPTS}" ${OPTS_LABEL}) - set(OPT "CMATE") - string(APPEND OPT "_${CMAKE_MATCH_1}") - string(REPLACE "-" "_" OPT "${OPT}") - string(TOUPPER ${OPT} OPT) +function(cmate_update_url URL ARGS) + cmate_deps_get_url(${URL}) + cmate_update_dep("${ARGS}") +endfunction() - if("${CMAKE_MATCH_3}" STREQUAL "") - cmate_setg(${OPT} 1) +function(cmate_update) + if(NOT EXISTS ${CMATE_DEPSFILE}) + cmate_msg("no dependencies") + return() + endif() + + file(STRINGS ${CMATE_DEPSFILE} DEPS) + + foreach(SPEC ${DEPS}) + if(SPEC MATCHES "^#") + # Skip comments + continue() + elseif(SPEC MATCHES "^([A-Za-z0-9_-]+)=(.+)$") + # Variable assignment + cmate_setg("CMATE_${CMAKE_MATCH_1}" "${CMAKE_MATCH_2}") + elseif(SPEC MATCHES "^([a-z]+://[^ ]+)([ ](.+))?$") + # URL + set(URL ${CMAKE_MATCH_1}) + set(ARGS "${CMAKE_MATCH_3}") + cmate_msg("checking ${URL}") + cmate_update_url(${URL} "${ARGS}") + elseif(SPEC MATCHES "^(([^: ]+):)?([^@ ]+)(@([^ ]+))?([ ](.+))?$") + # GitHub/GitLab style project short ref + if(CMAKE_MATCH_2) + if(CMATE_${CMAKE_MATCH_2}) + set(HOST ${CMATE_${CMAKE_MATCH_2}}) + else() + cmate_die("unknown id: ${CMAKE_MATCH_2}") + endif() else() - cmate_setg(${OPT} "${CMAKE_MATCH_3}") + set(HOST ${CMATE_${CMATE_GIT_HOST}}) endif() - elseif("${CMATE_CMD}" STREQUAL "") - set(CMATE_CMD "${CMAKE_ARGV${CMATE_POS}}") - set(OPTS_LABEL ${CMATE_CMD}) - set(OPTS_VAR CMATE_${CMATE_CMD}_OPTIONS) - string(TOUPPER "${OPTS_VAR}" OPTS_VAR) - set(OPTS ${${OPTS_VAR}}) + + set(REPO ${CMAKE_MATCH_3}) + set(TAG ${CMAKE_MATCH_5}) + set(ARGS "${CMAKE_MATCH_7}") + cmate_msg("checking ${REPO}") + cmate_update_repo(${HOST} ${REPO} "${TAG}" "${ARGS}") else() - list(APPEND CMATE_ARGS "${CMAKE_ARGV${CMATE_POS}}") + cmate_die("invalid dependency line: ${SPEC}") endif() + endforeach() +endfunction() +############################################################################### +# +# Content of cmate/commands/help.cmake +# +############################################################################### +set(CMATE_HELP_HEADER "CMate v${CMATE_VER}") +list(APPEND CMATE_CMDS "help") - math(EXPR CMATE_POS "${CMATE_POS}+1") - endwhile() +list( + APPEND + CMATE_OPTIONS + "verbose" +) - list(LENGTH CMATE_ARGS CMATE_ARGC) +function(cmate_build_help VAR) + set( + CMATE_HELP_PRE + " +Usage: cmate [OPTIONS] COMMAND - cmate_setg(CMATE_CMD "${CMATE_CMD}") - cmate_setg(CMATE_ARGS "${CMATE_ARGS}") - cmate_setg(CMATE_ARGC ${CMATE_ARGC}) - get_filename_component(CMATE_ENV "${CMATE_ENV}" REALPATH) - cmate_setg(CMATE_ENV ${CMATE_ENV}) +Options: + --verbose Verbose operation + +Commands: +" + ) + set( + CMATE_HELP_POST + "See 'cmate help ' to read about a specific subcommand." + ) + set(LENGTH 0) + string(APPEND HELP ${CMATE_HELP_PRE}) + + foreach(CMD ${CMATE_CMDS}) + string(LENGTH "${CMD}" CL) + + if(CL GREATER ${LENGTH}) + set(LENGTH ${CL}) + endif() + endforeach() + + foreach(CMD ${CMATE_CMDS}) + string(LENGTH "${CMD}" CL) + math(EXPR PAD "${LENGTH}-${CL}") + string(TOUPPER ${CMD} UCMD) + set(CHVAR "CMATE_${UCMD}_SHORT_HELP") + + string(REPEAT " " ${PAD} CPAD) + string(APPEND HELP " ${CMD}${CPAD} ${${CHVAR}}\n") + endforeach() + + string(APPEND HELP "\n${CMATE_HELP_POST}") + set(${VAR} ${HELP} PARENT_SCOPE) +endfunction() + +function(cmate_help) + set(HVAR "CMATE") + if(CMATE_ARGC GREATER 0) + # Sub command help + list(GET CMATE_ARGS 0 HCMD) + + if(${HCMD} IN_LIST CMATE_CMDS) + string(TOUPPER "${HCMD}" HCMD) + string(APPEND HVAR "_${HCMD}_HELP") + set(HELP ${${HVAR}}) + else() + cmate_die("no such command: ${HCMD}") + endif() + else() + # Global help + cmate_build_help("HELP") + endif() + + string(CONFIGURE ${HELP} HELP) + + message("${CMATE_HELP_HEADER}") + message(${HELP}) +endfunction() + +############################################################################## +# +# Target common functions +# +############################################################################## + + +############################################################################## +# +# Configuration functions +# +############################################################################## +function(cmate_set_defaults) + get_filename_component(DIR "." ABSOLUTE) + cmate_setg(CMATE_ROOT_DIR ${DIR}) + + get_filename_component(DIR ".cenv" ABSOLUTE) + cmate_setg(CMATE_ENV_DIR ${DIR}) + + get_filename_component(DIR ".cmate" ABSOLUTE) + cmate_setg(CMATE_HOME_DIR ${DIR}) + cmate_setg(CMATE_DEPS_DIR "${CMATE_HOME_DIR}/deps") + cmate_setg(CMATE_STATE_DIR "${CMATE_HOME_DIR}/state") + cmate_setg(CMATE_TOOLCHAINS_DIR "${CMATE_HOME_DIR}/toolchains") + + cmate_setg(CMATE_BUILD_DIR "${CMATE_ROOT_DIR}/build") + cmate_setg(CMATE_STAGE_DIR "${CMATE_ROOT_DIR}/stage") + + cmate_setg(CMATE_HEADER_PAT "*.hpp") + cmate_setg(CMATE_SOURCE_PAT "*.[ch]pp") endfunction() ############################################################################## @@ -908,20 +1376,15 @@ endfunction() function(cmate_process_cmd) if (CMATE_CMD STREQUAL "version") message(${CMATE_VERSION}) - elseif (CMATE_CMD STREQUAL "configure") - cmate_set_version() - cmate_configure() - elseif (CMATE_CMD STREQUAL "build") - cmate_build() - elseif (CMATE_CMD STREQUAL "stage") - cmate_stage() - elseif (CMATE_CMD STREQUAL "clean") - cmate_clean() - elseif (CMATE_CMD STREQUAL "help") - cmate_show_help() - elseif(CMATE_CMD) - cmate_msg("unknown command: ${CMATE_CMD}") - elseif(NOT CMATE_CMD) + elseif (CMATE_CMD) + set(CMATE_COMMAND "cmate_${CMATE_CMD}") + + if(COMMAND "${CMATE_COMMAND}") + cmake_language(CALL ${CMATE_COMMAND}) + else() + cmate_msg("unknown command: ${CMATE_CMD}") + endif() + else() cmate_msg("no command") endif() endfunction() @@ -931,9 +1394,9 @@ endfunction() # Main part # ############################################################################## -if(CMAKE_SCRIPT_MODE_FILE AND NOT CMAKE_PARENT_LIST_FILE) +if(CMAKE_SCRIPT_MODE_FILE) cmate_set_defaults() cmate_parse_arguments() - cmate_load_conf("${CMATE_ROOT_DIR}/${CMATE_CONF}") + cmate_load_conf("${CMATE_ROOT_DIR}/${CMATE_PRJFILE}") cmate_process_cmd() endif() diff --git a/cpp/deps.txt b/cpp/deps.txt index f96324184..95058ad50 100644 --- a/cpp/deps.txt +++ b/cpp/deps.txt @@ -1,2 +1,2 @@ nlohmann/json@v3.11.3 -DJSON_BuildTests=OFF -cucumber/messages@cpp-windows-ci --srcdir=cpp +cucumber/messages --srcdir=cpp diff --git a/cpp/cmate.json b/cpp/project.json similarity index 100% rename from cpp/cmate.json rename to cpp/project.json diff --git a/cpp/src/bin/gherkin-generate-tokens/cmate.json b/cpp/src/bin/gherkin-generate-tokens/link.json similarity index 100% rename from cpp/src/bin/gherkin-generate-tokens/cmate.json rename to cpp/src/bin/gherkin-generate-tokens/link.json diff --git a/cpp/src/bin/gherkin/cmate.json b/cpp/src/bin/gherkin/link.json similarity index 100% rename from cpp/src/bin/gherkin/cmate.json rename to cpp/src/bin/gherkin/link.json diff --git a/cpp/src/lib/gherkin/cmate.json b/cpp/src/lib/gherkin/link.json similarity index 100% rename from cpp/src/lib/gherkin/cmate.json rename to cpp/src/lib/gherkin/link.json From bfadff3611ce78662705e7427ceff45b56a5c60d Mon Sep 17 00:00:00 2001 From: Remy Chibois Date: Thu, 4 Jan 2024 17:51:34 +0100 Subject: [PATCH 3/4] chore: fix CI push path for cpp --- .github/workflows/test-cpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-cpp.yml b/.github/workflows/test-cpp.yml index ea84c8f33..d55812c0e 100644 --- a/.github/workflows/test-cpp.yml +++ b/.github/workflows/test-cpp.yml @@ -6,7 +6,7 @@ on: - main - renovate/** paths: - - cpp/** + - cpp* - testdata/** - gherkin-languages.json pull_request: From 20dd4b5582de6ad9211a996081f14f26f3bbd9cd Mon Sep 17 00:00:00 2001 From: Remy Chibois Date: Thu, 4 Jan 2024 17:54:52 +0100 Subject: [PATCH 4/4] chore: fix CI push path for cpp --- .github/workflows/test-cpp.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test-cpp.yml b/.github/workflows/test-cpp.yml index d55812c0e..0ea60fd06 100644 --- a/.github/workflows/test-cpp.yml +++ b/.github/workflows/test-cpp.yml @@ -13,7 +13,7 @@ on: branches: - main paths: - - cpp/** + - cpp* - testdata/** - gherkin-languages.json workflow_call: