From b2f034f90246a3dc5a2136b45e9f6845fe54152e Mon Sep 17 00:00:00 2001 From: FeignClaims Date: Wed, 11 Oct 2023 15:07:13 +0800 Subject: [PATCH 1/4] Make directories enabling recursively --- README.md | 12 ++- cmake/CppfrontHelpers.cmake | 183 ++++++++++++++++++++---------------- example/CMakeLists.txt | 2 +- example/{ => app}/main.cpp2 | 0 4 files changed, 113 insertions(+), 84 deletions(-) rename example/{ => app}/main.cpp2 (100%) diff --git a/README.md b/README.md index 342a665..494800d 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ FetchContent-only: ### Functions ```cmake -cppfront_generate_cpp( ...) +cppfront_generate_files( ...) ``` Writes to the variable named by `OUTVAR` a list of absolute paths to the generated `.cpp` files associated with @@ -125,9 +125,7 @@ each `.cpp2` file in the arguments list. A hashing scheme prevents `cppfront` fr multiple times. ```cmake -cppfront_enable( - TARGETS ... -) +cppfront_enable_targets(...) ``` Scans the `SOURCES` properties for each target in `` for entries ending in `.cpp2`. These are passed @@ -135,6 +133,12 @@ to `cppfront_generate_cpp` and the results are added to the target automatically unset (i.e. by default), this command runs on all targets in the directory that imported this package at the end of processing the directory. +```cmake +cppfront_enable_directories(...) +``` + +Recursively scans all targets inside `` and calls `cppfront_enable_targets` for them. + ### Developers The CMake project `regression-tests/CMakeLists.txt` runs the test suite of cppfront. diff --git a/cmake/CppfrontHelpers.cmake b/cmake/CppfrontHelpers.cmake index 891f20f..03fb385 100644 --- a/cmake/CppfrontHelpers.cmake +++ b/cmake/CppfrontHelpers.cmake @@ -1,91 +1,116 @@ -function(_cppfront_unique_name base hash outvar) - string(LENGTH "${hash}" len) - foreach (i RANGE 0 "${len}") - string(SUBSTRING "${hash}" 0 "${i}" uniq) - if (uniq) - set(name "${base}-${uniq}") - else () - set(name "${base}") - endif () - get_property(name_used GLOBAL PROPERTY "cppfront/names/${name}" SET) - if (NOT name_used) - set("${outvar}" "${name}" PARENT_SCOPE) - set_property(GLOBAL PROPERTY "cppfront/names/${name}" 1) - return() - endif () - endforeach () - # This should be impossible, unless caching in _cppfront_generate_source - # is broken. - message(FATAL_ERROR "Could not compute a unique name using ${base} and ${hash}") +function(_convert_path_relative_to_source_dir file out) + cmake_path(IS_RELATIVE file is_relative) + + if(is_relative) + cmake_path(ABSOLUTE_PATH file BASE_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} NORMALIZE) + endif() + + cmake_path(RELATIVE_PATH file BASE_DIRECTORY ${CMAKE_SOURCE_DIR}) + + set("${out}" "${file}" PARENT_SCOPE) endfunction() -function(_cppfront_generate_source src out) - file(REAL_PATH "${src}" src) - string(SHA256 src_hash "${src}") - - get_property(out_file GLOBAL PROPERTY "cppfront/out_file/${src_hash}") - if (out_file) - set("${out}" "${out_file}" PARENT_SCOPE) - return() - endif () - - cmake_path(GET src STEM original_stem) - _cppfront_unique_name("${original_stem}" "${src_hash}" basename) - - # assume no SHA256 collisions - file(MAKE_DIRECTORY "${CMAKE_BINARY_DIR}/_cppfront/") - if(src MATCHES [[.*\.h2]]) - set(ext ".h") - else() - set(ext ".cpp") - endif() - set(out_file "${CMAKE_BINARY_DIR}/_cppfront/${basename}${ext}") - - add_custom_command( - OUTPUT "${out_file}" - COMMAND cppfront::cppfront "${src}" -o "${out_file}" ${CPPFRONT_FLAGS} - DEPENDS cppfront::cppfront "${src}" - VERBATIM - ) - - set_property(GLOBAL PROPERTY "cppfront/out_file/${src_hash}" "${out_file}") - set("${out}" "${out_file}" PARENT_SCOPE) +function(_parse_relative_source relative_source out_absolute_source_file out_absolute_binary_file) + cmake_path(GET relative_source PARENT_PATH parent_path) + cmake_path(GET relative_source FILENAME filename) + cmake_path(GET filename STEM LAST_ONLY filestem) + cmake_path(GET relative_source EXTENSION LAST_ONLY extension) + + if(extension MATCHES "\.h2") + set(extension ".h") + else() + set(extension ".cpp") + endif() + + set(absolute_binary "${filestem}${extension}") + cmake_path(ABSOLUTE_PATH absolute_binary BASE_DIRECTORY "${CMAKE_BINARY_DIR}/${parent_path}/_cppfront/" NORMALIZE) + set("${out_absolute_binary_file}" "${absolute_binary}" PARENT_SCOPE) + + cmake_path(ABSOLUTE_PATH relative_source BASE_DIRECTORY "${CMAKE_SOURCE_DIR}" NORMALIZE OUTPUT_VARIABLE absolute_source) + set("${out_absolute_source_file}" "${absolute_source}" PARENT_SCOPE) endfunction() -function(cppfront_generate_cpp srcs) - set(cpp2srcs "") - foreach (src IN LISTS ARGN) - _cppfront_generate_source("${src}" cpp2) - list(APPEND cpp2srcs "${cpp2}") - endforeach () - set("${srcs}" "${cpp2srcs}" PARENT_SCOPE) +function(_cppfront_generate_file file out) + _convert_path_relative_to_source_dir("${file}" source_file) + + _parse_relative_source("${source_file}" absolute_source_file absolute_binary_file) + + add_custom_command( + OUTPUT "${absolute_binary_file}" + COMMAND cppfront::cppfront "${absolute_source_file}" -o "${absolute_binary_file}" ${CPPFRONT_FLAGS} + DEPENDS cppfront::cppfront "${absolute_source_file}" + COMMENT "Generating the corresponding cpp file" + VERBATIM + ) + + set("${out}" "${absolute_binary_file}" PARENT_SCOPE) endfunction() -function(cppfront_enable) - cmake_parse_arguments(PARSE_ARGV 0 ARG "" "" "TARGETS") +function(cppfront_generate_files out) + set(files "") - foreach (tgt IN LISTS ARG_TARGETS) - get_property(sources TARGET "${tgt}" PROPERTY SOURCES) - list(FILTER sources INCLUDE REGEX "\\.(cpp|h)2$") + foreach(file IN LISTS ARGN) + _cppfront_generate_file(${file} "output_file") + list(APPEND files "${output_file}") + endforeach() - if (sources) - target_link_libraries("${tgt}" PRIVATE cppfront::cpp2util) - cppfront_generate_cpp(cpp1sources ${sources}) - target_sources("${tgt}" PRIVATE ${cpp1sources}) - endif () - endforeach () + set("${out}" "${files}" PARENT_SCOPE) endfunction() -if (NOT CPPFRONT_NO_MAGIC) - function(_cppfront_enable_dir) - get_property(targets DIRECTORY . PROPERTY BUILDSYSTEM_TARGETS) - cppfront_enable(TARGETS ${targets}) - endfunction() +function(_cppfront_enable_target target) + get_property(cpp2sources TARGET "${target}" PROPERTY SOURCES) + list(FILTER cpp2sources INCLUDE REGEX "\\.(cpp|h)2$") + + if(cpp2sources) + target_link_libraries("${target}" PRIVATE cppfront::cpp2util) + get_property(source_dir TARGET "${target}" PROPERTY SOURCE_DIR) + + set(cpp2_absolute_sources "") + foreach(source IN LISTS cpp2sources) + cmake_path(IS_RELATIVE source is_relative) + if(is_relative) + cmake_path(ABSOLUTE_PATH source BASE_DIRECTORY ${source_dir} NORMALIZE) + endif() + list(APPEND cpp2_absolute_sources ${source}) + endforeach() + + cppfront_generate_files("cpp1sources" ${cpp2_absolute_sources}) - if (NOT _CPPFRONT_MAGIC_DIR) - set(_CPPFRONT_MAGIC_DIR "${CMAKE_CURRENT_SOURCE_DIR}") - endif () + add_custom_target("${target}.parse_cpp2" DEPENDS ${cpp1sources}) + add_dependencies("${target}" "${target}.parse_cpp2") + target_sources("${target}" PRIVATE ${cpp1sources}) + endif() +endfunction() + +function(cppfront_enable_targets) + foreach(target IN LISTS ARGN) + _cppfront_enable_target("${target}") + endforeach() +endfunction() + +function(_cppfront_enable_directory directory) + function(_cppfront_enable_current_dir directory) + get_property(targets DIRECTORY "${directory}" PROPERTY BUILDSYSTEM_TARGETS) + + cppfront_enable_targets(${targets}) + + get_property(subdirs DIRECTORY "${directory}" PROPERTY SUBDIRECTORIES) + + foreach(subdir IN LISTS subdirs) + _cppfront_enable_current_dir("${subdir}") + endforeach() + endfunction() + + message(STATUS "Enabling cppfront for all targets in ${directory}") + cmake_language(DEFER DIRECTORY "${directory}" CALL _cppfront_enable_current_dir "${directory}") +endfunction() + +function(cppfront_enable_directories) + foreach(directory IN LISTS ARGN) + _cppfront_enable_directory("${directory}") + endforeach() +endfunction() - message(VERBOSE "Enabling cppfront for all targets in ${_CPPFRONT_MAGIC_DIR}") - cmake_language(DEFER DIRECTORY "${_CPPFRONT_MAGIC_DIR}" CALL _cppfront_enable_dir) -endif () +if(NOT CPPFRONT_NO_MAGIC) + cppfront_enable_directories(${CMAKE_CURRENT_SOURCE_DIR}) +endif() diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index f92e1a8..f478387 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -5,4 +5,4 @@ find_package(cppfront REQUIRED) # This works, too: # add_subdirectory(../cppfront cppfront) -add_executable(main main.cpp2) +add_subdirectory(app) diff --git a/example/main.cpp2 b/example/app/main.cpp2 similarity index 100% rename from example/main.cpp2 rename to example/app/main.cpp2 From 68549387a2d4c8d8941086d68f1feee725cf4203 Mon Sep 17 00:00:00 2001 From: FeignClaims Date: Wed, 11 Oct 2023 15:31:58 +0800 Subject: [PATCH 2/4] Complete documentation --- README.md | 8 +++--- cmake/CppfrontHelpers.cmake | 53 +++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 494800d..e05d447 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,8 @@ No matter how you use this CMake build, it exposes the following points of confi Universal: -* `CPPFRONT_NO_MAGIC` -- off by default. When enabled, skips the automatic `cpp2`-to-`cpp` translation. +* `CPPFRONT_NO_MAGIC` -- disabled by default. When disabled, automatically translate `cpp2`-to-`cpp` for all + targets inside the directory where `find_package` is called. * `CPPFRONT_FLAGS` -- a semicolon-separated list of additional flags to pass to `cppfront`. For now, these are assumed to be universal to a project, and it is not supported to change them after the package has loaded, whether via `find_package`, `add_subdirectory`, FetchContent, or any other mechanism. @@ -121,15 +122,14 @@ cppfront_generate_files( ...) ``` Writes to the variable named by `OUTVAR` a list of absolute paths to the generated `.cpp` files associated with -each `.cpp2` file in the arguments list. A hashing scheme prevents `cppfront` from running on the same `.cpp2` file -multiple times. +each `.cpp2` file in the arguments list. ```cmake cppfront_enable_targets(...) ``` Scans the `SOURCES` properties for each target in `` for entries ending in `.cpp2`. These are passed -to `cppfront_generate_cpp` and the results are added to the target automatically. When `CPPFRONT_NO_MAGIC` is +to `cppfront_generate_files` and the results are added to the target automatically. When `CPPFRONT_NO_MAGIC` is unset (i.e. by default), this command runs on all targets in the directory that imported this package at the end of processing the directory. diff --git a/cmake/CppfrontHelpers.cmake b/cmake/CppfrontHelpers.cmake index 03fb385..41384af 100644 --- a/cmake/CppfrontHelpers.cmake +++ b/cmake/CppfrontHelpers.cmake @@ -1,3 +1,29 @@ +# - Helpers for cppfront usage +# This module provides helpers for cppfront usage +# +# These variables can affects the behaviour of this module: +# +# CPPFRONT_NO_MAGIC: +# +# Disabled by default. +# When disabled, automatically translate `cpp2` to `cpp` for all targets +# inside the directory where this module is included. +# +# CPPFRONT_FLAGS: +# +# a semicolon-separated list of additional flags to pass to `cppfront`. +# +# This function translates `cpp2` to `cpp`: +# +# cppfront_generate_files( ...) +# +# These function enables `cpp2`-to-`cpp` translation for targets or targets in directories: +# +# cppfront_enable_targets(...) +# cppfront_enable_directories(...) + +include_guard() + function(_convert_path_relative_to_source_dir file out) cmake_path(IS_RELATIVE file is_relative) @@ -10,6 +36,7 @@ function(_convert_path_relative_to_source_dir file out) set("${out}" "${file}" PARENT_SCOPE) endfunction() +# Parse the cpp2 `source` that is relative to `CMAKE_SOURCE_DIR`. function(_parse_relative_source relative_source out_absolute_source_file out_absolute_binary_file) cmake_path(GET relative_source PARENT_PATH parent_path) cmake_path(GET relative_source FILENAME filename) @@ -30,6 +57,8 @@ function(_parse_relative_source relative_source out_absolute_source_file out_abs set("${out_absolute_source_file}" "${absolute_source}" PARENT_SCOPE) endfunction() +# Writes to the variable named by `OUTVAR` a absolute path to the generated +# `.cpp` file associated with the `.cpp2` file in the arguments list. function(_cppfront_generate_file file out) _convert_path_relative_to_source_dir("${file}" source_file) @@ -46,6 +75,11 @@ function(_cppfront_generate_file file out) set("${out}" "${absolute_binary_file}" PARENT_SCOPE) endfunction() +# cppfront_generate_files( ...) +# +# Writes to the variable named by `OUTVAR` a list of absolute paths to the +# generated `.cpp` files associated with each `.cpp2` file in the arguments +# list. function(cppfront_generate_files out) set(files "") @@ -57,6 +91,11 @@ function(cppfront_generate_files out) set("${out}" "${files}" PARENT_SCOPE) endfunction() +# Scans the `SOURCES` properties for `` for entries ending in `.cpp2`. +# These are passed to `cppfront_generate_files` and the results are added to the +# target automatically. When `CPPFRONT_NO_MAGIC` is unset (i.e. by default), +# this command runs on all targets in the directory that imported this package +# at the end of processing the directory. function(_cppfront_enable_target target) get_property(cpp2sources TARGET "${target}" PROPERTY SOURCES) list(FILTER cpp2sources INCLUDE REGEX "\\.(cpp|h)2$") @@ -82,12 +121,20 @@ function(_cppfront_enable_target target) endif() endfunction() +# cppfront_enable_targets(...) +# +# Scans the `SOURCES` properties for `` for entries ending in `.cpp2`. +# These are passed to `cppfront_generate_cpp` and the results are added to the +# target automatically. When `CPPFRONT_NO_MAGIC` is unset (i.e. by default), +# this command runs on all targets in the directory that imported this package +# at the end of processing the directory. function(cppfront_enable_targets) foreach(target IN LISTS ARGN) _cppfront_enable_target("${target}") endforeach() endfunction() +# Recursively scans all targets inside `` and calls `cppfront_enable_targets` for them. function(_cppfront_enable_directory directory) function(_cppfront_enable_current_dir directory) get_property(targets DIRECTORY "${directory}" PROPERTY BUILDSYSTEM_TARGETS) @@ -105,12 +152,18 @@ function(_cppfront_enable_directory directory) cmake_language(DEFER DIRECTORY "${directory}" CALL _cppfront_enable_current_dir "${directory}") endfunction() +# cppfront_enable_directories(...) +# +# Recursively scans all targets inside `` and calls +# `cppfront_enable_targets` for them. function(cppfront_enable_directories) foreach(directory IN LISTS ARGN) _cppfront_enable_directory("${directory}") endforeach() endfunction() +# If `CPPFRONT_NO_MAGIC` not enabled, automatically translate `cpp2`-to-`cpp` +# for all targets inside the directory where this module is included. if(NOT CPPFRONT_NO_MAGIC) cppfront_enable_directories(${CMAKE_CURRENT_SOURCE_DIR}) endif() From 2189d7b9b25647748eb65a7b1b1ef4709f713080 Mon Sep 17 00:00:00 2001 From: FeignClaims Date: Wed, 11 Oct 2023 15:47:50 +0800 Subject: [PATCH 3/4] Put generated cpp files in _cppfront inside bindir --- cmake/CppfrontHelpers.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/CppfrontHelpers.cmake b/cmake/CppfrontHelpers.cmake index 41384af..7b063be 100644 --- a/cmake/CppfrontHelpers.cmake +++ b/cmake/CppfrontHelpers.cmake @@ -50,7 +50,7 @@ function(_parse_relative_source relative_source out_absolute_source_file out_abs endif() set(absolute_binary "${filestem}${extension}") - cmake_path(ABSOLUTE_PATH absolute_binary BASE_DIRECTORY "${CMAKE_BINARY_DIR}/${parent_path}/_cppfront/" NORMALIZE) + cmake_path(ABSOLUTE_PATH absolute_binary BASE_DIRECTORY "${CMAKE_BINARY_DIR}/_cppfront/${parent_path}/" NORMALIZE) set("${out_absolute_binary_file}" "${absolute_binary}" PARENT_SCOPE) cmake_path(ABSOLUTE_PATH relative_source BASE_DIRECTORY "${CMAKE_SOURCE_DIR}" NORMALIZE OUTPUT_VARIABLE absolute_source) From 3055f502a5eff7ea5c29f8391682f2cb7ee49979 Mon Sep 17 00:00:00 2001 From: FeignClaims Date: Wed, 11 Oct 2023 17:04:32 +0800 Subject: [PATCH 4/4] Make directory before cpp2 translation --- cmake/CppfrontHelpers.cmake | 9 ++++++--- example/app/CMakeLists.txt | 1 + 2 files changed, 7 insertions(+), 3 deletions(-) create mode 100644 example/app/CMakeLists.txt diff --git a/cmake/CppfrontHelpers.cmake b/cmake/CppfrontHelpers.cmake index 7b063be..6b6f0d0 100644 --- a/cmake/CppfrontHelpers.cmake +++ b/cmake/CppfrontHelpers.cmake @@ -64,11 +64,14 @@ function(_cppfront_generate_file file out) _parse_relative_source("${source_file}" absolute_source_file absolute_binary_file) + cmake_path(GET absolute_binary_file PARENT_PATH binary_directory) + add_custom_command( - OUTPUT "${absolute_binary_file}" + OUTPUT ${absolute_binary_file} + COMMAND ${CMAKE_COMMAND} -E make_directory ${binary_directory} COMMAND cppfront::cppfront "${absolute_source_file}" -o "${absolute_binary_file}" ${CPPFRONT_FLAGS} DEPENDS cppfront::cppfront "${absolute_source_file}" - COMMENT "Generating the corresponding cpp file" + COMMENT "Generating ${absolute_binary_file}" VERBATIM ) @@ -117,7 +120,7 @@ function(_cppfront_enable_target target) add_custom_target("${target}.parse_cpp2" DEPENDS ${cpp1sources}) add_dependencies("${target}" "${target}.parse_cpp2") - target_sources("${target}" PRIVATE ${cpp1sources}) + target_sources("${target}" PRIVATE "${cpp1sources}") endif() endfunction() diff --git a/example/app/CMakeLists.txt b/example/app/CMakeLists.txt new file mode 100644 index 0000000..36eac36 --- /dev/null +++ b/example/app/CMakeLists.txt @@ -0,0 +1 @@ +add_executable(main main.cpp2) \ No newline at end of file