From 7e24602bce1584a5d1ecda541a8b5f7b3eddcf8a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 17:07:27 +0000 Subject: [PATCH 1/4] Apply YAML formatter fixes --- .github/workflows/clang-format-fix.yaml | 15 ++++++++------- .github/workflows/clang-tidy-fix.yaml | 4 +++- .github/workflows/cmake-format-fix.yaml | 15 ++++++++------- .github/workflows/codeql-analysis.yaml | 8 +------- .github/workflows/header-guards-fix.yaml | 15 ++++++++------- .github/workflows/jsonnet-format-fix.yaml | 15 ++++++++------- .github/workflows/markdown-fix.yaml | 15 ++++++++------- .github/workflows/python-fix.yaml | 15 ++++++++------- .github/workflows/yaml-fix.yaml | 15 ++++++++------- 9 files changed, 60 insertions(+), 57 deletions(-) diff --git a/.github/workflows/clang-format-fix.yaml b/.github/workflows/clang-format-fix.yaml index e19d86be..a9c045c9 100644 --- a/.github/workflows/clang-format-fix.yaml +++ b/.github/workflows/clang-format-fix.yaml @@ -8,7 +8,9 @@ run-name: "${{ github.actor }} fixing C++ code format" workflow_dispatch: inputs: ref: - description: "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the repository's default branch." + description: + "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the + repository's default branch." required: false type: string workflow_call: @@ -52,8 +54,7 @@ permissions: contents: write env: - local_checkout_path: - ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} + local_checkout_path: ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} jobs: pre-check: @@ -70,11 +71,11 @@ jobs: # This covers repo owners, invited collaborators, and all org members. outputs: ref: - ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && - (github.event.inputs.ref || github.ref_name)) || steps.get_pr.outputs.ref }} + ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && (github.event.inputs.ref || github.ref_name)) || + steps.get_pr.outputs.ref }} repo: - ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && - github.repository) || steps.get_pr.outputs.repo }} + ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && github.repository) || steps.get_pr.outputs.repo + }} steps: - name: Get PR Info diff --git a/.github/workflows/clang-tidy-fix.yaml b/.github/workflows/clang-tidy-fix.yaml index 092ddd0d..4fa8d0fd 100644 --- a/.github/workflows/clang-tidy-fix.yaml +++ b/.github/workflows/clang-tidy-fix.yaml @@ -8,7 +8,9 @@ name: Clang-Tidy Fix workflow_dispatch: inputs: ref: - description: "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the repository's default branch." + description: + "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the + repository's default branch." required: false type: string tidy-checks: diff --git a/.github/workflows/cmake-format-fix.yaml b/.github/workflows/cmake-format-fix.yaml index 2bb6f639..6b6269f6 100644 --- a/.github/workflows/cmake-format-fix.yaml +++ b/.github/workflows/cmake-format-fix.yaml @@ -8,7 +8,9 @@ run-name: "${{ github.actor }} fixing CMake format" workflow_dispatch: inputs: ref: - description: "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the repository's default branch." + description: + "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the + repository's default branch." required: false type: string workflow_call: @@ -52,8 +54,7 @@ permissions: contents: write env: - local_checkout_path: - ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} + local_checkout_path: ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} jobs: pre-check: @@ -70,11 +71,11 @@ jobs: # This covers repo owners, invited collaborators, and all org members. outputs: ref: - ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && - (github.event.inputs.ref || github.ref_name)) || steps.get_pr.outputs.ref }} + ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && (github.event.inputs.ref || github.ref_name)) || + steps.get_pr.outputs.ref }} repo: - ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && - github.repository) || steps.get_pr.outputs.repo }} + ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && github.repository) || steps.get_pr.outputs.repo + }} steps: - name: Get PR Info diff --git a/.github/workflows/codeql-analysis.yaml b/.github/workflows/codeql-analysis.yaml index a87081bd..665430b8 100644 --- a/.github/workflows/codeql-analysis.yaml +++ b/.github/workflows/codeql-analysis.yaml @@ -218,13 +218,7 @@ jobs: fi determine-languages: - needs: - [ - pre-check, - detect-changes-cpp, - detect-changes-python, - detect-changes-actions, - ] + needs: [pre-check, detect-changes-cpp, detect-changes-python, detect-changes-actions] if: always() && needs.pre-check.result == 'success' runs-on: ubuntu-latest outputs: diff --git a/.github/workflows/header-guards-fix.yaml b/.github/workflows/header-guards-fix.yaml index 2c0f7fb6..5abea8d3 100644 --- a/.github/workflows/header-guards-fix.yaml +++ b/.github/workflows/header-guards-fix.yaml @@ -43,7 +43,9 @@ run-name: "${{ github.actor }} fixing header guards" workflow_dispatch: inputs: ref: - description: "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the repository's default branch." + description: + "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the + repository's default branch." required: false type: string @@ -52,8 +54,7 @@ permissions: contents: write env: - local_checkout_path: - ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} + local_checkout_path: ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} jobs: pre-check: @@ -70,11 +71,11 @@ jobs: # This covers repo owners, invited collaborators, and all org members. outputs: ref: - ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && - (github.event.inputs.ref || github.ref_name)) || steps.get_pr.outputs.ref }} + ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && (github.event.inputs.ref || github.ref_name)) || + steps.get_pr.outputs.ref }} repo: - ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && - github.repository) || steps.get_pr.outputs.repo }} + ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && github.repository) || steps.get_pr.outputs.repo + }} steps: - name: Get PR Info diff --git a/.github/workflows/jsonnet-format-fix.yaml b/.github/workflows/jsonnet-format-fix.yaml index 5a02e4aa..1f721e9b 100644 --- a/.github/workflows/jsonnet-format-fix.yaml +++ b/.github/workflows/jsonnet-format-fix.yaml @@ -8,7 +8,9 @@ run-name: "${{ github.actor }} fixing Jsonnet format" workflow_dispatch: inputs: ref: - description: "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the repository's default branch." + description: + "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the + repository's default branch." required: false type: string workflow_call: @@ -52,8 +54,7 @@ permissions: contents: write env: - local_checkout_path: - ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} + local_checkout_path: ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} jobs: pre-check: @@ -70,11 +71,11 @@ jobs: # This covers repo owners, invited collaborators, and all org members. outputs: ref: - ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && - (github.event.inputs.ref || github.ref_name)) || steps.get_pr.outputs.ref }} + ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && (github.event.inputs.ref || github.ref_name)) || + steps.get_pr.outputs.ref }} repo: - ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && - github.repository) || steps.get_pr.outputs.repo }} + ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && github.repository) || steps.get_pr.outputs.repo + }} steps: - name: Get PR Info diff --git a/.github/workflows/markdown-fix.yaml b/.github/workflows/markdown-fix.yaml index bee7f76e..e0150475 100644 --- a/.github/workflows/markdown-fix.yaml +++ b/.github/workflows/markdown-fix.yaml @@ -43,7 +43,9 @@ run-name: "${{ github.actor }} fixing Markdown format" workflow_dispatch: inputs: ref: - description: "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the repository's default branch." + description: + "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the + repository's default branch." required: false type: string @@ -52,8 +54,7 @@ permissions: contents: write env: - local_checkout_path: - ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} + local_checkout_path: ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} jobs: pre-check: @@ -70,11 +71,11 @@ jobs: # This covers repo owners, invited collaborators, and all org members. outputs: ref: - ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && - (github.event.inputs.ref || github.ref_name)) || steps.get_pr.outputs.ref }} + ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && (github.event.inputs.ref || github.ref_name)) || + steps.get_pr.outputs.ref }} repo: - ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && - github.repository) || steps.get_pr.outputs.repo }} + ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && github.repository) || steps.get_pr.outputs.repo + }} steps: - name: Get PR Info diff --git a/.github/workflows/python-fix.yaml b/.github/workflows/python-fix.yaml index 1f2bcc05..c9961213 100644 --- a/.github/workflows/python-fix.yaml +++ b/.github/workflows/python-fix.yaml @@ -8,7 +8,9 @@ run-name: "${{ github.actor }} fixing Python code" workflow_dispatch: inputs: ref: - description: "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the repository's default branch." + description: + "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the + repository's default branch." required: false type: string workflow_call: @@ -52,8 +54,7 @@ permissions: contents: write env: - local_checkout_path: - ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} + local_checkout_path: ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} jobs: pre-check: @@ -70,11 +71,11 @@ jobs: # This covers repo owners, invited collaborators, and all org members. outputs: ref: - ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && - (github.event.inputs.ref || github.ref_name)) || steps.get_pr.outputs.ref }} + ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && (github.event.inputs.ref || github.ref_name)) || + steps.get_pr.outputs.ref }} repo: - ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && - github.repository) || steps.get_pr.outputs.repo }} + ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && github.repository) || steps.get_pr.outputs.repo + }} steps: - name: Get PR Info if: github.event_name == 'issue_comment' && inputs.ref == '' diff --git a/.github/workflows/yaml-fix.yaml b/.github/workflows/yaml-fix.yaml index 36c9f5c5..cbb53491 100644 --- a/.github/workflows/yaml-fix.yaml +++ b/.github/workflows/yaml-fix.yaml @@ -8,7 +8,9 @@ name: YAML Fix workflow_dispatch: inputs: ref: - description: "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the repository's default branch." + description: + "The branch name to checkout and push fixes to (must be a branch, not a commit SHA). Defaults to the + repository's default branch." required: false type: string workflow_call: @@ -52,8 +54,7 @@ permissions: contents: write env: - local_checkout_path: - ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} + local_checkout_path: ${{ inputs.checkout-path || format('{0}-src', github.event.repository.name) }} jobs: pre-check: @@ -70,11 +71,11 @@ jobs: # This covers repo owners, invited collaborators, and all org members. outputs: ref: - ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && - (github.event.inputs.ref || github.ref_name)) || steps.get_pr.outputs.ref }} + ${{ inputs.ref || (github.event_name == 'workflow_dispatch' && (github.event.inputs.ref || github.ref_name)) || + steps.get_pr.outputs.ref }} repo: - ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && - github.repository) || steps.get_pr.outputs.repo }} + ${{ inputs.repo || (github.event_name == 'workflow_dispatch' && github.repository) || steps.get_pr.outputs.repo + }} steps: - name: Get PR Info From 439d3166bcbbbcf2dba9e809611af31a3bf4c9e3 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 9 Mar 2026 16:52:29 +0000 Subject: [PATCH 2/4] Add symbol visibility armoring to all shared libraries (de novo on main) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create PhlexSymbolVisibility.cmake with phlex_apply_symbol_visibility() that generates export headers into centralized ${PROJECT_BINARY_DIR}/include, sets CXX_VISIBILITY_PRESET hidden + VISIBILITY_INLINES_HIDDEN ON, and installs the headers for downstream consumers. Apply phlex_apply_symbol_visibility() to all 5 shared libraries: phlex_utilities, phlex_model, phlex_core, phlex_configuration_internal, run_phlex. Annotate ~45 headers across the whole phlex namespace (including phlex::experimental) with export macros — every non-template class and free function with a .cpp implementation. Also add missing includes flagged by misc-include-cleaner: - and to identifier.hpp - to hashing.hpp - to load_module.hpp Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Apply clang-format fixes Export tag_invoke customization points in configuration.hpp The Boost.JSON customization point overloads for configuration, product_query, and experimental::identifier were hidden by the visibility policy, causing config_test link failure: undefined reference to phlex::tag_invoke(boost::json::value_to_tag...) phlex::tag_invoke(boost::json::value_to_tag...) These are public API symbols (they back value_to() for JSON deserialization) that were missed in the initial visibility sweep. Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Export missing symbols causing undefined-reference link failures Three non-template free functions had .cpp implementations but were missing export macros, causing linker failures in test executables: - phlex_model_EXPORT on friend operator== / operator<=> for identifier_query in identifier.hpp (called from identifier test) - phlex_core_EXPORT on detail::verify_name in glue.hpp (called from template instantiations of glue::provide/observe/transform/...) - phlex_core_EXPORT on port_index_for and more_derived in message.hpp (called from template instantiations in observer_node et al.) Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Export to_product_specifications, output_api, and product_store::more_derived Three more non-template symbols with .cpp implementations were missing export macros, causing linker failures across most test executables: - phlex_model_EXPORT on to_product_specifications() in product_specification.hpp (called from declared_transform.hpp and declared_fold.hpp template instantiations in every test binary) - phlex_core_EXPORT on output_api class in registration_api.hpp (constructor called from glue::output template instantiations) - phlex_model_EXPORT on more_derived(product_store_ptr, product_store_ptr) in product_store.hpp (distinct from the message::more_derived fixed earlier; called directly from product_store test and from template get_most_derived) Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Apply clang-format fixes Add _internal companion libraries for test access and size/timing comparison Introduce phlex_make_internal_library(target LIBRARIES ...) in PhlexSymbolVisibility.cmake. The function: - reads SOURCES from the already-defined public target (no duplication) - handles generated sources (configure_file output) via src/bin dir fallback - creates ${target}_internal SHARED using add_library (not cet_make_library) so cetmodules never registers it for installation or package export - propagates $ PUBLIC so consumers such as layer_generator_internal can resolve phlex/* headers - propagates COMPILE_DEFINITIONS and COMPILE_OPTIONS from the public target - omits CXX_VISIBILITY_PRESET hidden so all symbols are visible by default Applied to all four non-trivial shared libraries: phlex_utilities, phlex_model, phlex_core, run_phlex The _internal chain is phlex_core_internal -> phlex_model_internal -> phlex_utilities_internal so tests linking only to phlex::core_internal get all internal symbols transitively without loading the public .so files. layer_generator_internal added in plugins/CMakeLists.txt (same sources, links PRIVATE phlex_core_internal) to avoid loading both the visibility-hidden and all-visible phlex_core variants in the same test process (ODR). All tests in test/CMakeLists.txt and test/utilities/CMakeLists.txt switched to the _internal variants, except: - config_test and identifier which need phlex::configuration and thus transitively pull in the public phlex_core/model/utilities libs; since the relevant symbols are already exported these tests are fine on the public libraries - type_deduction which only requires the header-only phlex::metaprogramming Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Move export headers from include/ to include/phlex/ Generate and install phlex_X_export.hpp files under include/phlex/ instead of flat in include/, matching the layout of all other Phlex installed headers. Update every #include "X_export.hpp" directive in the 42 affected public headers to #include "phlex/X_export.hpp". The target_include_directories entries are unchanged — the base paths (PROJECT_BINARY_DIR/include for build, include for install) already resolve correctly once the phlex/ subdirectory is part of the filename. Co-authored-by: pcanal <5175087+pcanal@users.noreply.github.com> Remove redundant INSTALL_INTERFACE from phlex_apply_symbol_visibility cetmodules adds INSTALL_INTERFACE:include to every target it creates via cet_make_library, so the explicit INSTALL_INTERFACE:include entry in phlex_apply_symbol_visibility was a no-op duplicate. The only unique contribution of the target_include_directories call is the BUILD_INTERFACE to ${PROJECT_BINARY_DIR}/include, which is where generate_export_header writes the generated phlex/X_export.hpp headers. Co-authored-by: pcanal <5175087+pcanal@users.noreply.github.com> Apply cmake-format fixes --- CMakeLists.txt | 1 + Modules/private/PhlexSymbolVisibility.cmake | 95 +++++++++++++++++++++ phlex/CMakeLists.txt | 1 + phlex/app/CMakeLists.txt | 9 ++ phlex/app/load_module.hpp | 16 +++- phlex/app/run.hpp | 4 +- phlex/app/version.hpp | 4 +- phlex/concurrency.hpp | 4 +- phlex/configuration.hpp | 20 +++-- phlex/core/CMakeLists.txt | 9 ++ phlex/core/consumer.hpp | 4 +- phlex/core/declared_fold.hpp | 4 +- phlex/core/declared_observer.hpp | 4 +- phlex/core/declared_output.hpp | 4 +- phlex/core/declared_predicate.hpp | 4 +- phlex/core/declared_provider.hpp | 4 +- phlex/core/declared_transform.hpp | 4 +- phlex/core/declared_unfold.hpp | 6 +- phlex/core/detail/filter_impl.hpp | 6 +- phlex/core/detail/make_algorithm_name.hpp | 5 +- phlex/core/detail/maybe_predicates.hpp | 5 +- phlex/core/detail/repeater_node.hpp | 5 +- phlex/core/edge_creation_policy.hpp | 4 +- phlex/core/edge_maker.hpp | 4 +- phlex/core/filter.hpp | 4 +- phlex/core/framework_graph.hpp | 4 +- phlex/core/glue.hpp | 6 +- phlex/core/index_router.hpp | 8 +- phlex/core/input_arguments.hpp | 6 +- phlex/core/message.hpp | 10 ++- phlex/core/node_catalog.hpp | 4 +- phlex/core/product_query.hpp | 4 +- phlex/core/products_consumer.hpp | 4 +- phlex/core/registrar.hpp | 5 +- phlex/core/registration_api.hpp | 4 +- phlex/core/store_counters.hpp | 6 +- phlex/model/CMakeLists.txt | 9 ++ phlex/model/algorithm_name.hpp | 4 +- phlex/model/data_cell_counter.hpp | 8 +- phlex/model/data_cell_index.hpp | 6 +- phlex/model/data_layer_hierarchy.hpp | 4 +- phlex/model/identifier.hpp | 15 ++-- phlex/model/product_matcher.hpp | 4 +- phlex/model/product_specification.hpp | 11 ++- phlex/model/product_store.hpp | 7 +- phlex/model/products.hpp | 6 +- phlex/utilities/CMakeLists.txt | 9 ++ phlex/utilities/hashing.hpp | 11 ++- phlex/utilities/resource_usage.hpp | 4 +- plugins/CMakeLists.txt | 6 ++ test/CMakeLists.txt | 84 +++++++++--------- test/utilities/CMakeLists.txt | 6 +- 52 files changed, 362 insertions(+), 123 deletions(-) create mode 100644 Modules/private/PhlexSymbolVisibility.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index dad56423..c67482ad 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,7 @@ set(CTEST_TEST_TIMEOUT 90 CACHE STRING "Per-test timeout (s) for CTest") FetchContent_MakeAvailable(Catch2 GSL mimicpp) include(Modules/private/CreateCoverageTargets.cmake) +include(Modules/private/PhlexSymbolVisibility.cmake) option(ENABLE_TSAN "Enable Thread Sanitizer" OFF) option(ENABLE_ASAN "Enable Address Sanitizer" OFF) diff --git a/Modules/private/PhlexSymbolVisibility.cmake b/Modules/private/PhlexSymbolVisibility.cmake new file mode 100644 index 00000000..d2dd906e --- /dev/null +++ b/Modules/private/PhlexSymbolVisibility.cmake @@ -0,0 +1,95 @@ +include(GenerateExportHeader) + +function(phlex_apply_symbol_visibility target) + set(EXPORT_HEADER "${PROJECT_BINARY_DIR}/include/phlex/${target}_export.hpp") + set(EXPORT_MACRO_NAME "${target}_EXPORT") + + generate_export_header( + ${target} + BASE_NAME ${target} + EXPORT_FILE_NAME ${EXPORT_HEADER} + EXPORT_MACRO_NAME ${EXPORT_MACRO_NAME} + STATIC_DEFINE "${target}_STATIC_DEFINE" + ) + + set_target_properties( + ${target} + PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON + ) + + target_include_directories(${target} PUBLIC $) + + install(FILES "${EXPORT_HEADER}" DESTINATION include/phlex) +endfunction() + +# Create a non-installed companion library _internal with default (visible) symbol +# visibility for all symbols. This allows tests to access non-exported implementation +# details without requiring every internal symbol to carry an EXPORT macro, and enables +# before/after comparison of library/executable sizes and link/load times. +# +# Usage (in the same CMakeLists.txt that defines ): +# phlex_make_internal_library( LIBRARIES [PUBLIC ...] [PRIVATE ...]) +# +# The LIBRARIES arguments mirror those of the original cet_make_library call but may +# substitute other _internal targets for the corresponding public ones so that the +# full transitive symbol set is visible. +function(phlex_make_internal_library target) + cmake_parse_arguments(ARG "" "" "LIBRARIES" ${ARGN}) + + set(internal "${target}_internal") + + # Retrieve sources and source directory from the public target so we don't + # have to maintain a separate source list. + get_target_property(srcs ${target} SOURCES) + if(NOT srcs) + message(FATAL_ERROR "phlex_make_internal_library: ${target} has no SOURCES property") + endif() + get_target_property(src_dir ${target} SOURCE_DIR) + get_target_property(bin_dir ${target} BINARY_DIR) + + # Convert relative paths to absolute. Generated sources (e.g. configure_file + # output) live in the binary directory rather than the source directory. + set(abs_srcs "") + foreach(s IN LISTS srcs) + if(IS_ABSOLUTE "${s}") + list(APPEND abs_srcs "${s}") + elseif(EXISTS "${src_dir}/${s}") + list(APPEND abs_srcs "${src_dir}/${s}") + else() + list(APPEND abs_srcs "${bin_dir}/${s}") + endif() + endforeach() + + # Use add_library directly (not cet_make_library) so that cetmodules does not + # register this target for installation or package export. + add_library(${internal} SHARED ${abs_srcs}) + + if(ARG_LIBRARIES) + target_link_libraries(${internal} ${ARG_LIBRARIES}) + endif() + + # Cetmodules automatically adds $ for + # libraries it manages; replicate that here so consumers (e.g. layer_generator_internal) + # can resolve project headers such as #include "phlex/core/...". + # The _export.hpp headers live in PROJECT_BINARY_DIR/include/phlex. + # Without CXX_VISIBILITY_PRESET hidden the export macros expand to the default + # visibility attribute, making every symbol visible — exactly what we want here. + target_include_directories( + ${internal} + PUBLIC + "$" + "$" + ) + + # Propagate compile definitions and options that the public target carries + # (e.g. BOOST_DLL_USE_STD_FS for run_phlex) so the internal build is equivalent. + get_target_property(defs ${target} COMPILE_DEFINITIONS) + if(defs) + target_compile_definitions(${internal} PRIVATE ${defs}) + endif() + + get_target_property(opts ${target} COMPILE_OPTIONS) + if(opts) + target_compile_options(${internal} PRIVATE ${opts}) + endif() +endfunction() diff --git a/phlex/CMakeLists.txt b/phlex/CMakeLists.txt index f208a812..e81b7002 100644 --- a/phlex/CMakeLists.txt +++ b/phlex/CMakeLists.txt @@ -33,6 +33,7 @@ cet_make_library( Boost::json phlex::core ) +phlex_apply_symbol_visibility(phlex_configuration_internal) cet_make_library( LIBRARY_NAME diff --git a/phlex/app/CMakeLists.txt b/phlex/app/CMakeLists.txt index 3c0a57af..42ccc9ca 100644 --- a/phlex/app/CMakeLists.txt +++ b/phlex/app/CMakeLists.txt @@ -18,10 +18,19 @@ cet_make_library( ) install(FILES load_module.hpp run.hpp version.hpp DESTINATION include/phlex/app) +phlex_apply_symbol_visibility(run_phlex) # We'll use C++17's filesystem instead of Boost's target_compile_definitions(run_phlex PRIVATE BOOST_DLL_USE_STD_FS) +phlex_make_internal_library( + run_phlex + LIBRARIES + PUBLIC phlex_core_internal Boost::json Boost::boost +) +# BOOST_DLL_USE_STD_FS is propagated from run_phlex's COMPILE_DEFINITIONS by +# phlex_make_internal_library, so no explicit repeat is needed here. + cet_make_exec( NAME phlex SOURCE phlex.cpp diff --git a/phlex/app/load_module.hpp b/phlex/app/load_module.hpp index 14d3ba1f..20fbcc3b 100644 --- a/phlex/app/load_module.hpp +++ b/phlex/app/load_module.hpp @@ -1,23 +1,31 @@ #ifndef PHLEX_APP_LOAD_MODULE_HPP #define PHLEX_APP_LOAD_MODULE_HPP +#include "phlex/run_phlex_export.hpp" + #include "phlex/core/fwd.hpp" #include "phlex/driver.hpp" #include "boost/json.hpp" #include +#include namespace phlex::experimental { namespace detail { // Adjust_config adds the module_label as a parameter, and it checks if the 'py' // parameter exists, inserting the 'cpp: "pymodule"' configuration if necessary. - boost::json::object adjust_config(std::string const& label, boost::json::object raw_config); + run_phlex_EXPORT boost::json::object adjust_config(std::string const& label, + boost::json::object raw_config); } - void load_module(framework_graph& g, std::string const& label, boost::json::object config); - void load_source(framework_graph& g, std::string const& label, boost::json::object config); - detail::next_index_t load_driver(boost::json::object const& config); + run_phlex_EXPORT void load_module(framework_graph& g, + std::string const& label, + boost::json::object config); + run_phlex_EXPORT void load_source(framework_graph& g, + std::string const& label, + boost::json::object config); + run_phlex_EXPORT detail::next_index_t load_driver(boost::json::object const& config); } #endif // PHLEX_APP_LOAD_MODULE_HPP diff --git a/phlex/app/run.hpp b/phlex/app/run.hpp index 96161b77..af4ab113 100644 --- a/phlex/app/run.hpp +++ b/phlex/app/run.hpp @@ -1,12 +1,14 @@ #ifndef PHLEX_APP_RUN_HPP #define PHLEX_APP_RUN_HPP +#include "phlex/run_phlex_export.hpp" + #include "boost/json.hpp" #include namespace phlex::experimental { - void run(boost::json::object const& configurations, int max_parallelism); + run_phlex_EXPORT void run(boost::json::object const& configurations, int max_parallelism); } #endif // PHLEX_APP_RUN_HPP diff --git a/phlex/app/version.hpp b/phlex/app/version.hpp index ec1dbe94..dfb9b93c 100644 --- a/phlex/app/version.hpp +++ b/phlex/app/version.hpp @@ -1,7 +1,9 @@ #ifndef PHLEX_APP_VERSION_HPP #define PHLEX_APP_VERSION_HPP +#include "phlex/run_phlex_export.hpp" + namespace phlex::experimental { - char const* version(); + run_phlex_EXPORT char const* version(); } #endif // PHLEX_APP_VERSION_HPP diff --git a/phlex/concurrency.hpp b/phlex/concurrency.hpp index b456b913..cb98595f 100644 --- a/phlex/concurrency.hpp +++ b/phlex/concurrency.hpp @@ -1,10 +1,12 @@ #ifndef PHLEX_CONCURRENCY_HPP #define PHLEX_CONCURRENCY_HPP +#include "phlex/phlex_core_export.hpp" + #include namespace phlex { - struct concurrency { + struct phlex_core_EXPORT concurrency { static concurrency const unlimited; static concurrency const serial; diff --git a/phlex/configuration.hpp b/phlex/configuration.hpp index 7dcf3945..1a5ec1ef 100644 --- a/phlex/configuration.hpp +++ b/phlex/configuration.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CONFIGURATION_HPP #define PHLEX_CONFIGURATION_HPP +#include "phlex/phlex_configuration_internal_export.hpp" + #include "boost/json.hpp" #include "phlex/core/product_query.hpp" #include "phlex/model/identifier.hpp" @@ -22,8 +24,8 @@ namespace phlex { } // Used later for product_query - std::optional value_if_exists(boost::json::object const& obj, - std::string_view parameter); + phlex_configuration_internal_EXPORT std::optional + value_if_exists(boost::json::object const& obj, std::string_view parameter); // helper for unpacking json array template @@ -34,7 +36,7 @@ namespace phlex { } } - class configuration { + class phlex_configuration_internal_EXPORT configuration { public: configuration() = default; explicit configuration(boost::json::object const& config) : config_{config} {} @@ -89,15 +91,15 @@ namespace phlex { // To enable direct conversions from Boost JSON types to our own types, we implement // tag_invoke(...) function overloads, which are the customization points Boost JSON // provides. - configuration tag_invoke(boost::json::value_to_tag const&, - boost::json::value const& jv); + phlex_configuration_internal_EXPORT configuration + tag_invoke(boost::json::value_to_tag const&, boost::json::value const& jv); - product_query tag_invoke(boost::json::value_to_tag const&, - boost::json::value const& jv); + phlex_configuration_internal_EXPORT product_query + tag_invoke(boost::json::value_to_tag const&, boost::json::value const& jv); namespace experimental { - identifier tag_invoke(boost::json::value_to_tag const&, - boost::json::value const& jv); + phlex_configuration_internal_EXPORT identifier + tag_invoke(boost::json::value_to_tag const&, boost::json::value const& jv); } template diff --git a/phlex/core/CMakeLists.txt b/phlex/core/CMakeLists.txt index 36fd293a..6e31ad98 100644 --- a/phlex/core/CMakeLists.txt +++ b/phlex/core/CMakeLists.txt @@ -81,6 +81,7 @@ install( DESTINATION include/phlex/core/detail ) target_include_directories(phlex_core PRIVATE ${PROJECT_SOURCE_DIR}) +phlex_apply_symbol_visibility(phlex_core) # AppleClang 15.0 still treats std::views::join as experimental if( @@ -90,6 +91,14 @@ if( target_compile_options(phlex_core PRIVATE "-fexperimental-library") endif() +phlex_make_internal_library( + phlex_core + LIBRARIES + PUBLIC TBB::tbb phlex::metaprogramming phlex_model_internal phlex_utilities_internal + PRIVATE Boost::json spdlog::spdlog +) +add_library(phlex::core_internal ALIAS phlex_core_internal) + # Interface library cet_make_library( LIBRARY_NAME diff --git a/phlex/core/consumer.hpp b/phlex/core/consumer.hpp index fbd38b05..bc4c70a0 100644 --- a/phlex/core/consumer.hpp +++ b/phlex/core/consumer.hpp @@ -1,13 +1,15 @@ #ifndef PHLEX_CORE_CONSUMER_HPP #define PHLEX_CORE_CONSUMER_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/model/algorithm_name.hpp" #include #include namespace phlex::experimental { - class consumer { + class phlex_core_EXPORT consumer { public: consumer(algorithm_name name, std::vector predicates); diff --git a/phlex/core/declared_fold.hpp b/phlex/core/declared_fold.hpp index 4a641532..429a252d 100644 --- a/phlex/core/declared_fold.hpp +++ b/phlex/core/declared_fold.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DECLARED_FOLD_HPP #define PHLEX_CORE_DECLARED_FOLD_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/concurrency.hpp" #include "phlex/core/concepts.hpp" #include "phlex/core/fold/send.hpp" @@ -34,7 +36,7 @@ #include namespace phlex::experimental { - class declared_fold : public products_consumer { + class phlex_core_EXPORT declared_fold : public products_consumer { public: declared_fold(algorithm_name name, std::vector predicates, diff --git a/phlex/core/declared_observer.hpp b/phlex/core/declared_observer.hpp index d1bea85e..fc3e6d0e 100644 --- a/phlex/core/declared_observer.hpp +++ b/phlex/core/declared_observer.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DECLARED_OBSERVER_HPP #define PHLEX_CORE_DECLARED_OBSERVER_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/concepts.hpp" #include "phlex/core/fwd.hpp" #include "phlex/core/input_arguments.hpp" @@ -30,7 +32,7 @@ namespace phlex::experimental { - class declared_observer : public products_consumer { + class phlex_core_EXPORT declared_observer : public products_consumer { public: declared_observer(algorithm_name name, std::vector predicates, diff --git a/phlex/core/declared_output.hpp b/phlex/core/declared_output.hpp index 7ca82f4f..4e264358 100644 --- a/phlex/core/declared_output.hpp +++ b/phlex/core/declared_output.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DECLARED_OUTPUT_HPP #define PHLEX_CORE_DECLARED_OUTPUT_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/consumer.hpp" #include "phlex/core/fwd.hpp" #include "phlex/core/message.hpp" @@ -20,7 +22,7 @@ namespace phlex::experimental { namespace detail { using output_function_t = std::function; } - class declared_output : public consumer { + class phlex_core_EXPORT declared_output : public consumer { public: declared_output(algorithm_name name, std::size_t concurrency, diff --git a/phlex/core/declared_predicate.hpp b/phlex/core/declared_predicate.hpp index 72643c7d..755d8b29 100644 --- a/phlex/core/declared_predicate.hpp +++ b/phlex/core/declared_predicate.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DECLARED_PREDICATE_HPP #define PHLEX_CORE_DECLARED_PREDICATE_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/concepts.hpp" #include "phlex/core/detail/filter_impl.hpp" #include "phlex/core/fwd.hpp" @@ -32,7 +34,7 @@ namespace phlex::experimental { - class declared_predicate : public products_consumer { + class phlex_core_EXPORT declared_predicate : public products_consumer { public: declared_predicate(algorithm_name name, std::vector predicates, diff --git a/phlex/core/declared_provider.hpp b/phlex/core/declared_provider.hpp index 33576de6..9ade62ef 100644 --- a/phlex/core/declared_provider.hpp +++ b/phlex/core/declared_provider.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DECLARED_PROVIDER_HPP #define PHLEX_CORE_DECLARED_PROVIDER_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/concepts.hpp" #include "phlex/core/fwd.hpp" #include "phlex/core/message.hpp" @@ -22,7 +24,7 @@ namespace phlex::experimental { - class declared_provider { + class phlex_core_EXPORT declared_provider { public: declared_provider(algorithm_name name, product_query output_product); virtual ~declared_provider(); diff --git a/phlex/core/declared_transform.hpp b/phlex/core/declared_transform.hpp index 34358cd8..8e9586c2 100644 --- a/phlex/core/declared_transform.hpp +++ b/phlex/core/declared_transform.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DECLARED_TRANSFORM_HPP #define PHLEX_CORE_DECLARED_TRANSFORM_HPP +#include "phlex/phlex_core_export.hpp" + // FIXME: Add comments explaining the process. For each implementation, explain what part // of the process a given section of code is addressing. @@ -36,7 +38,7 @@ namespace phlex::experimental { - class declared_transform : public products_consumer { + class phlex_core_EXPORT declared_transform : public products_consumer { public: declared_transform(algorithm_name name, std::vector predicates, diff --git a/phlex/core/declared_unfold.hpp b/phlex/core/declared_unfold.hpp index 8d5010cf..8952f6f3 100644 --- a/phlex/core/declared_unfold.hpp +++ b/phlex/core/declared_unfold.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DECLARED_UNFOLD_HPP #define PHLEX_CORE_DECLARED_UNFOLD_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/concepts.hpp" #include "phlex/core/fwd.hpp" #include "phlex/core/input_arguments.hpp" @@ -32,7 +34,7 @@ namespace phlex::experimental { - class generator { + class phlex_core_EXPORT generator { public: explicit generator(product_store_const_ptr const& parent, algorithm_name node_name, @@ -53,7 +55,7 @@ namespace phlex::experimental { std::map child_counts_; }; - class declared_unfold : public products_consumer { + class phlex_core_EXPORT declared_unfold : public products_consumer { public: declared_unfold(algorithm_name name, std::vector predicates, diff --git a/phlex/core/detail/filter_impl.hpp b/phlex/core/detail/filter_impl.hpp index 4d6dcd2d..0277ee87 100644 --- a/phlex/core/detail/filter_impl.hpp +++ b/phlex/core/detail/filter_impl.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DETAIL_FILTER_IMPL_HPP #define PHLEX_CORE_DETAIL_FILTER_IMPL_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/fwd.hpp" #include "phlex/core/product_query.hpp" #include "phlex/model/product_store.hpp" @@ -29,7 +31,7 @@ namespace phlex::experimental { return value == true_value; } - class decision_map { + class phlex_core_EXPORT decision_map { using decisions_t = oneapi::tbb::concurrent_hash_map; public: @@ -47,7 +49,7 @@ namespace phlex::experimental { decisions_t results_; }; - class data_map { + class phlex_core_EXPORT data_map { using stores_t = oneapi::tbb::concurrent_hash_map>; diff --git a/phlex/core/detail/make_algorithm_name.hpp b/phlex/core/detail/make_algorithm_name.hpp index 2edde613..b554e1b9 100644 --- a/phlex/core/detail/make_algorithm_name.hpp +++ b/phlex/core/detail/make_algorithm_name.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DETAIL_MAKE_ALGORITHM_NAME_HPP #define PHLEX_CORE_DETAIL_MAKE_ALGORITHM_NAME_HPP +#include "phlex/phlex_core_export.hpp" + // This simple utility is placed in an implementation file to avoid including the // phlex/configuration.hpp in framework code. @@ -14,7 +16,8 @@ namespace phlex::experimental { class algorithm_name; namespace detail { - algorithm_name make_algorithm_name(configuration const* config, std::string_view name); + phlex_core_EXPORT algorithm_name make_algorithm_name(configuration const* config, + std::string_view name); } } diff --git a/phlex/core/detail/maybe_predicates.hpp b/phlex/core/detail/maybe_predicates.hpp index 196915d7..f48c33a8 100644 --- a/phlex/core/detail/maybe_predicates.hpp +++ b/phlex/core/detail/maybe_predicates.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DETAIL_MAYBE_PREDICATES_HPP #define PHLEX_CORE_DETAIL_MAYBE_PREDICATES_HPP +#include "phlex/phlex_core_export.hpp" + // This simple utility is placed in an implementation file to avoid including the // phlex/configuration.hpp in framework code. @@ -13,7 +15,8 @@ namespace phlex { } namespace phlex::experimental::detail { - std::optional> maybe_predicates(configuration const* config); + phlex_core_EXPORT std::optional> maybe_predicates( + configuration const* config); } #endif // PHLEX_CORE_DETAIL_MAYBE_PREDICATES_HPP diff --git a/phlex/core/detail/repeater_node.hpp b/phlex/core/detail/repeater_node.hpp index eb9ba978..1b48fec9 100644 --- a/phlex/core/detail/repeater_node.hpp +++ b/phlex/core/detail/repeater_node.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_DETAIL_REPEATER_NODE_HPP #define PHLEX_CORE_DETAIL_REPEATER_NODE_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/message.hpp" #include "oneapi/tbb/concurrent_hash_map.h" @@ -15,7 +17,8 @@ namespace phlex::experimental::detail { using repeater_node_input = std::tuple; - class repeater_node : public tbb::flow::composite_node> { + class phlex_core_EXPORT repeater_node : + public tbb::flow::composite_node> { public: repeater_node(tbb::flow::graph& g, std::string node_name, identifier layer_name); diff --git a/phlex/core/edge_creation_policy.hpp b/phlex/core/edge_creation_policy.hpp index b6f0783e..caede8b7 100644 --- a/phlex/core/edge_creation_policy.hpp +++ b/phlex/core/edge_creation_policy.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_EDGE_CREATION_POLICY_HPP #define PHLEX_CORE_EDGE_CREATION_POLICY_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/message.hpp" #include "phlex/model/identifier.hpp" #include "phlex/model/product_specification.hpp" @@ -15,7 +17,7 @@ namespace phlex::experimental { using product_name_t = identifier; - class edge_creation_policy { + class phlex_core_EXPORT edge_creation_policy { public: template edge_creation_policy(Args&... producers); diff --git a/phlex/core/edge_maker.hpp b/phlex/core/edge_maker.hpp index fb4bf328..a40a4602 100644 --- a/phlex/core/edge_maker.hpp +++ b/phlex/core/edge_maker.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_EDGE_MAKER_HPP #define PHLEX_CORE_EDGE_MAKER_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/declared_fold.hpp" #include "phlex/core/declared_output.hpp" #include "phlex/core/declared_provider.hpp" @@ -28,7 +30,7 @@ namespace phlex::experimental { index_router::provider_input_ports_t make_provider_edges(index_router::head_ports_t head_ports, declared_providers& providers); - class edge_maker { + class phlex_core_EXPORT edge_maker { public: template edge_maker(Args&... args); diff --git a/phlex/core/filter.hpp b/phlex/core/filter.hpp index 36ccac00..b96b116a 100644 --- a/phlex/core/filter.hpp +++ b/phlex/core/filter.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_FILTER_HPP #define PHLEX_CORE_FILTER_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/detail/filter_impl.hpp" #include "phlex/core/fwd.hpp" #include "phlex/core/message.hpp" @@ -12,7 +14,7 @@ namespace phlex::experimental { oneapi::tbb::flow::composite_node, std::tuple>; - class filter : public filter_base { + class phlex_core_EXPORT filter : public filter_base { using indexer_t = oneapi::tbb::flow::indexer_node; using tag_t = indexer_t::output_type; diff --git a/phlex/core/framework_graph.hpp b/phlex/core/framework_graph.hpp index 49a1a6c0..c45f426f 100644 --- a/phlex/core/framework_graph.hpp +++ b/phlex/core/framework_graph.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_FRAMEWORK_GRAPH_HPP #define PHLEX_CORE_FRAMEWORK_GRAPH_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/declared_fold.hpp" #include "phlex/core/declared_unfold.hpp" #include "phlex/core/filter.hpp" @@ -31,7 +33,7 @@ namespace phlex { } namespace phlex::experimental { - class framework_graph { + class phlex_core_EXPORT framework_graph { public: explicit framework_graph(data_cell_index_ptr index, int max_parallelism = oneapi::tbb::info::default_concurrency()); diff --git a/phlex/core/glue.hpp b/phlex/core/glue.hpp index 86d47e12..1b8c008b 100644 --- a/phlex/core/glue.hpp +++ b/phlex/core/glue.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_GLUE_HPP #define PHLEX_CORE_GLUE_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/concurrency.hpp" #include "phlex/core/concepts.hpp" #include "phlex/core/registrar.hpp" @@ -23,7 +25,7 @@ namespace phlex::experimental { struct node_catalog; namespace detail { - void verify_name(std::string const& name, configuration const* config); + phlex_core_EXPORT void verify_name(std::string const& name, configuration const* config); } // ============================================================================== @@ -39,7 +41,7 @@ namespace phlex::experimental { * This object is stored as a shared pointer and its methods are bound to the created nodes. */ template - class glue { + class phlex_core_EXPORT glue { public: glue(tbb::flow::graph& g, node_catalog& nodes, diff --git a/phlex/core/index_router.hpp b/phlex/core/index_router.hpp index b15065eb..0fbfdfd2 100644 --- a/phlex/core/index_router.hpp +++ b/phlex/core/index_router.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_INDEX_ROUTER_HPP #define PHLEX_CORE_INDEX_ROUTER_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/fwd.hpp" #include "phlex/core/message.hpp" #include "phlex/model/data_cell_counter.hpp" @@ -30,7 +32,7 @@ namespace phlex::experimental { // join operation. It: // (a) routes index messages to either the matching layer or its data-layer parent, and // (b) emits flush tokens to the repeater to evict a cached data product from memory. - class multilayer_slot { + class phlex_core_EXPORT multilayer_slot { public: multilayer_slot(tbb::flow::graph& g, identifier layer, @@ -55,7 +57,7 @@ namespace phlex::experimental { // A layer_scope object is an RAII object that manages layer-scoped operations during // data-cell-index routing. It updates flush counters on construction and ensures cleanup // (flushing end tokens and releasing fold results) on destruction. - class layer_scope { + class phlex_core_EXPORT layer_scope { public: layer_scope(flush_counters& counters, flusher_t& flusher, @@ -74,7 +76,7 @@ namespace phlex::experimental { }; } - class index_router { + class phlex_core_EXPORT index_router { public: struct named_input_port { product_query product_label; diff --git a/phlex/core/input_arguments.hpp b/phlex/core/input_arguments.hpp index c2286787..6ed74aed 100644 --- a/phlex/core/input_arguments.hpp +++ b/phlex/core/input_arguments.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_INPUT_ARGUMENTS_HPP #define PHLEX_CORE_INPUT_ARGUMENTS_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/message.hpp" #include "phlex/core/product_query.hpp" #include "phlex/model/handle.hpp" @@ -56,8 +58,8 @@ namespace phlex::experimental { } namespace detail { - void verify_no_duplicate_input_products(std::string const& algorithm_name, - product_queries to_sort); + phlex_core_EXPORT void verify_no_duplicate_input_products(std::string const& algorithm_name, + product_queries to_sort); } template diff --git a/phlex/core/message.hpp b/phlex/core/message.hpp index bea2af04..62f42322 100644 --- a/phlex/core/message.hpp +++ b/phlex/core/message.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_MESSAGE_HPP #define PHLEX_CORE_MESSAGE_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/fwd.hpp" #include "phlex/core/product_query.hpp" #include "phlex/model/fwd.hpp" @@ -44,7 +46,7 @@ namespace phlex::experimental { std::size_t id; }; - struct message_matcher { + struct phlex_core_EXPORT message_matcher { std::size_t operator()(message const& msg) const noexcept; }; @@ -62,13 +64,13 @@ namespace phlex::experimental { using named_index_ports = std::vector; // Overload for use with most_derived - message const& more_derived(message const& a, message const& b); + phlex_core_EXPORT message const& more_derived(message const& a, message const& b); // Non-template overload for single message case inline message const& most_derived(message const& msg) { return msg; } - std::size_t port_index_for(product_queries const& product_labels, - product_query const& product_label); + phlex_core_EXPORT std::size_t port_index_for(product_queries const& product_labels, + product_query const& product_label); } #endif // PHLEX_CORE_MESSAGE_HPP diff --git a/phlex/core/node_catalog.hpp b/phlex/core/node_catalog.hpp index 447f11d4..68051aaa 100644 --- a/phlex/core/node_catalog.hpp +++ b/phlex/core/node_catalog.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_NODE_CATALOG_HPP #define PHLEX_CORE_NODE_CATALOG_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/declared_fold.hpp" #include "phlex/core/declared_observer.hpp" #include "phlex/core/declared_output.hpp" @@ -17,7 +19,7 @@ #include namespace phlex::experimental { - struct node_catalog { + struct phlex_core_EXPORT node_catalog { template auto registrar_for(std::vector& errors) { diff --git a/phlex/core/product_query.hpp b/phlex/core/product_query.hpp index dfd73bb6..dd0f4859 100644 --- a/phlex/core/product_query.hpp +++ b/phlex/core/product_query.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_PRODUCT_QUERY_HPP #define PHLEX_CORE_PRODUCT_QUERY_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/model/identifier.hpp" #include "phlex/model/product_specification.hpp" #include "phlex/model/type_id.hpp" @@ -63,7 +65,7 @@ namespace phlex { }; } - struct product_query { + struct phlex_core_EXPORT product_query { detail::required_creator_name creator; detail::required_layer_name layer; std::optional suffix; diff --git a/phlex/core/products_consumer.hpp b/phlex/core/products_consumer.hpp index c6ae79c0..180b6b7d 100644 --- a/phlex/core/products_consumer.hpp +++ b/phlex/core/products_consumer.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_PRODUCTS_CONSUMER_HPP #define PHLEX_CORE_PRODUCTS_CONSUMER_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/consumer.hpp" #include "phlex/core/fwd.hpp" #include "phlex/core/input_arguments.hpp" @@ -15,7 +17,7 @@ #include namespace phlex::experimental { - class products_consumer : public consumer { + class phlex_core_EXPORT products_consumer : public consumer { public: products_consumer(algorithm_name name, std::vector predicates, diff --git a/phlex/core/registrar.hpp b/phlex/core/registrar.hpp index d51fa32e..82ae79d5 100644 --- a/phlex/core/registrar.hpp +++ b/phlex/core/registrar.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_REGISTRAR_HPP #define PHLEX_CORE_REGISTRAR_HPP +#include "phlex/phlex_core_export.hpp" + // ======================================================================================= // // The registrar class completes the registration of a node at the end of a registration @@ -58,7 +60,8 @@ namespace phlex::experimental { namespace detail { - void add_to_error_messages(std::vector& errors, std::string const& name); + phlex_core_EXPORT void add_to_error_messages(std::vector& errors, + std::string const& name); } template diff --git a/phlex/core/registration_api.hpp b/phlex/core/registration_api.hpp index ce4d8e5b..93a7532a 100644 --- a/phlex/core/registration_api.hpp +++ b/phlex/core/registration_api.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_REGISTRATION_API_HPP #define PHLEX_CORE_REGISTRATION_API_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/concurrency.hpp" #include "phlex/core/concepts.hpp" #include "phlex/core/declared_fold.hpp" @@ -304,7 +306,7 @@ namespace phlex::experimental { // ==================================================================================== // Output API - class output_api { + class phlex_core_EXPORT output_api { public: output_api(registrar reg, configuration const* config, diff --git a/phlex/core/store_counters.hpp b/phlex/core/store_counters.hpp index 8363a93d..0e97b9f5 100644 --- a/phlex/core/store_counters.hpp +++ b/phlex/core/store_counters.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_CORE_STORE_COUNTERS_HPP #define PHLEX_CORE_STORE_COUNTERS_HPP +#include "phlex/phlex_core_export.hpp" + #include "phlex/core/fwd.hpp" #include "phlex/model/data_cell_counter.hpp" #include "phlex/model/data_cell_index.hpp" @@ -14,7 +16,7 @@ #include namespace phlex::experimental { - class store_counter { + class phlex_core_EXPORT store_counter { public: void set_flush_value(flush_counts_ptr counts, std::size_t original_message_id); void increment(data_cell_index::hash_type layer_hash); @@ -35,7 +37,7 @@ namespace phlex::experimental { std::atomic ready_to_flush_{true}; }; - class count_stores { + class phlex_core_EXPORT count_stores { protected: store_counter& counter_for(data_cell_index::hash_type hash); std::unique_ptr done_with(data_cell_index::hash_type hash); diff --git a/phlex/model/CMakeLists.txt b/phlex/model/CMakeLists.txt index 6b5eabf2..3209bf43 100644 --- a/phlex/model/CMakeLists.txt +++ b/phlex/model/CMakeLists.txt @@ -40,6 +40,15 @@ install( ) target_include_directories(phlex_model PRIVATE ${PROJECT_SOURCE_DIR}) +phlex_apply_symbol_visibility(phlex_model) + +phlex_make_internal_library( + phlex_model + LIBRARIES + PUBLIC Boost::boost spdlog::spdlog fmt::fmt + PRIVATE phlex_utilities_internal TBB::tbb +) +add_library(phlex::model_internal ALIAS phlex_model_internal) # Interface library cet_make_library( diff --git a/phlex/model/algorithm_name.hpp b/phlex/model/algorithm_name.hpp index 13970440..778f1080 100644 --- a/phlex/model/algorithm_name.hpp +++ b/phlex/model/algorithm_name.hpp @@ -1,10 +1,12 @@ #ifndef PHLEX_MODEL_ALGORITHM_NAME_HPP #define PHLEX_MODEL_ALGORITHM_NAME_HPP +#include "phlex/phlex_model_export.hpp" + #include "phlex/model/identifier.hpp" namespace phlex::experimental { - class algorithm_name { + class phlex_model_EXPORT algorithm_name { enum class specified_fields { neither, either, both }; public: diff --git a/phlex/model/data_cell_counter.hpp b/phlex/model/data_cell_counter.hpp index 6cbd615c..888a7da2 100644 --- a/phlex/model/data_cell_counter.hpp +++ b/phlex/model/data_cell_counter.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_MODEL_DATA_CELL_COUNTER_HPP #define PHLEX_MODEL_DATA_CELL_COUNTER_HPP +#include "phlex/phlex_model_export.hpp" + #include "phlex/model/data_cell_index.hpp" #include "phlex/model/fwd.hpp" #include "phlex/model/identifier.hpp" @@ -12,7 +14,7 @@ #include namespace phlex::experimental { - class flush_counts { + class phlex_model_EXPORT flush_counts { public: flush_counts(); explicit flush_counts(std::map child_counts); @@ -34,7 +36,7 @@ namespace phlex::experimental { std::map child_counts_{}; }; - class data_cell_counter { + class phlex_model_EXPORT data_cell_counter { public: data_cell_counter(); data_cell_counter(data_cell_counter* parent, identifier const& layer_name); @@ -57,7 +59,7 @@ namespace phlex::experimental { std::map child_counts_{}; }; - class flush_counters { + class phlex_model_EXPORT flush_counters { public: void update(data_cell_index_ptr const id); flush_counts extract(data_cell_index_ptr const id); diff --git a/phlex/model/data_cell_index.hpp b/phlex/model/data_cell_index.hpp index d4bdc83f..18c64325 100644 --- a/phlex/model/data_cell_index.hpp +++ b/phlex/model/data_cell_index.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_MODEL_DATA_CELL_INDEX_HPP #define PHLEX_MODEL_DATA_CELL_INDEX_HPP +#include "phlex/phlex_model_export.hpp" + #include "phlex/model/fwd.hpp" #include "phlex/model/identifier.hpp" @@ -14,7 +16,7 @@ #include namespace phlex { - class data_cell_index : public std::enable_shared_from_this { + class phlex_model_EXPORT data_cell_index : public std::enable_shared_from_this { public: static data_cell_index const& base(); static data_cell_index_ptr base_ptr(); @@ -51,7 +53,7 @@ namespace phlex { hash_type hash_{0}; }; - std::ostream& operator<<(std::ostream& os, data_cell_index const& id); + phlex_model_EXPORT std::ostream& operator<<(std::ostream& os, data_cell_index const& id); } namespace std { diff --git a/phlex/model/data_layer_hierarchy.hpp b/phlex/model/data_layer_hierarchy.hpp index 8e03819a..426aefd3 100644 --- a/phlex/model/data_layer_hierarchy.hpp +++ b/phlex/model/data_layer_hierarchy.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_MODEL_DATA_LAYER_HIERARCHY_HPP #define PHLEX_MODEL_DATA_LAYER_HIERARCHY_HPP +#include "phlex/phlex_model_export.hpp" + #include "phlex/model/data_cell_index.hpp" #include "phlex/model/fwd.hpp" @@ -13,7 +15,7 @@ namespace phlex::experimental { - class data_layer_hierarchy { + class phlex_model_EXPORT data_layer_hierarchy { public: ~data_layer_hierarchy(); void increment_count(data_cell_index_ptr const& id); diff --git a/phlex/model/identifier.hpp b/phlex/model/identifier.hpp index 89769117..cc002bcb 100644 --- a/phlex/model/identifier.hpp +++ b/phlex/model/identifier.hpp @@ -1,10 +1,14 @@ #ifndef PHLEX_MODEL_IDENTIFIER_HPP #define PHLEX_MODEL_IDENTIFIER_HPP +#include "phlex/phlex_model_export.hpp" + #include #include +#include +#include #include #include #include @@ -18,7 +22,7 @@ namespace phlex::experimental { /// Carries around the string itself (as a shared_ptr to string to make copies lighter) /// along with a precomputed hash used for all comparisons - class identifier { + class phlex_model_EXPORT identifier { public: static std::uint64_t hash_string(std::string_view str); // The default constructor is necessary so other classes containing identifiers @@ -56,8 +60,9 @@ namespace phlex::experimental { std::string const& trans_get_string() const noexcept { return content_; } // Comparison operators with _id queries - friend bool operator==(identifier const& lhs, identifier_query rhs); - friend std::strong_ordering operator<=>(identifier const& lhs, identifier_query rhs); + friend phlex_model_EXPORT bool operator==(identifier const& lhs, identifier_query rhs); + friend phlex_model_EXPORT std::strong_ordering operator<=>(identifier const& lhs, + identifier_query rhs); friend std::hash; private: @@ -67,8 +72,8 @@ namespace phlex::experimental { // Identifier UDL namespace literals { - identifier operator""_id(char const* lit, std::size_t len); - identifier_query operator""_idq(char const* lit, std::size_t len); + phlex_model_EXPORT identifier operator""_id(char const* lit, std::size_t len); + phlex_model_EXPORT identifier_query operator""_idq(char const* lit, std::size_t len); } // Really trying to avoid the extra function call here diff --git a/phlex/model/product_matcher.hpp b/phlex/model/product_matcher.hpp index 632273f0..e6f13bde 100644 --- a/phlex/model/product_matcher.hpp +++ b/phlex/model/product_matcher.hpp @@ -9,13 +9,15 @@ // // ======================================================================================= +#include "phlex/phlex_model_export.hpp" + #include "phlex/model/fwd.hpp" #include #include namespace phlex::experimental { - class product_matcher { + class phlex_model_EXPORT product_matcher { public: explicit product_matcher(std::string matcher_spec); bool matches(product_store_const_ptr const& store) const; diff --git a/phlex/model/product_specification.hpp b/phlex/model/product_specification.hpp index 5167f474..35de9f0d 100644 --- a/phlex/model/product_specification.hpp +++ b/phlex/model/product_specification.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_MODEL_PRODUCT_SPECIFICATION_HPP #define PHLEX_MODEL_PRODUCT_SPECIFICATION_HPP +#include "phlex/phlex_model_export.hpp" + #include "phlex/model/algorithm_name.hpp" #include "phlex/model/identifier.hpp" #include "phlex/model/type_id.hpp" @@ -12,7 +14,7 @@ #include namespace phlex::experimental { - class product_specification { + class phlex_model_EXPORT product_specification { public: product_specification(); product_specification(char const* name); @@ -44,9 +46,10 @@ namespace phlex::experimental { using product_specifications = std::vector; - product_specifications to_product_specifications(std::string_view name, - std::vector output_labels, - std::vector output_types); + phlex_model_EXPORT product_specifications + to_product_specifications(std::string_view name, + std::vector output_labels, + std::vector output_types); } template <> diff --git a/phlex/model/product_store.hpp b/phlex/model/product_store.hpp index 23199001..bbe29bc8 100644 --- a/phlex/model/product_store.hpp +++ b/phlex/model/product_store.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_MODEL_PRODUCT_STORE_HPP #define PHLEX_MODEL_PRODUCT_STORE_HPP +#include "phlex/phlex_model_export.hpp" + #include "phlex/model/algorithm_name.hpp" #include "phlex/model/data_cell_index.hpp" #include "phlex/model/fwd.hpp" @@ -15,7 +17,7 @@ #include namespace phlex::experimental { - class product_store { + class phlex_model_EXPORT product_store { public: explicit product_store(data_cell_index_ptr id, algorithm_name source = default_source(), @@ -58,7 +60,8 @@ namespace phlex::experimental { source_; // FIXME: Should not have to copy (the source should outlive the product store) }; - product_store_ptr const& more_derived(product_store_ptr const& a, product_store_ptr const& b); + phlex_model_EXPORT product_store_ptr const& more_derived(product_store_ptr const& a, + product_store_ptr const& b); // Non-template overload for single product_store_ptr case inline product_store_ptr const& most_derived(product_store_ptr const& store) { return store; } diff --git a/phlex/model/products.hpp b/phlex/model/products.hpp index d4ca44d9..60601423 100644 --- a/phlex/model/products.hpp +++ b/phlex/model/products.hpp @@ -1,6 +1,8 @@ #ifndef PHLEX_MODEL_PRODUCTS_HPP #define PHLEX_MODEL_PRODUCTS_HPP +#include "phlex/phlex_model_export.hpp" + #include "phlex/model/product_specification.hpp" #include @@ -12,7 +14,7 @@ namespace phlex::experimental { - struct product_base { + struct phlex_model_EXPORT product_base { virtual ~product_base() = default; virtual void const* address() const = 0; virtual std::type_info const& type() const = 0; @@ -32,7 +34,7 @@ namespace phlex::experimental { std::remove_cvref_t obj; }; - class products { + class phlex_model_EXPORT products { using collection_t = std::unordered_map>; public: diff --git a/phlex/utilities/CMakeLists.txt b/phlex/utilities/CMakeLists.txt index cc6c0228..def3a769 100644 --- a/phlex/utilities/CMakeLists.txt +++ b/phlex/utilities/CMakeLists.txt @@ -27,6 +27,15 @@ install( ) target_include_directories(phlex_utilities PRIVATE ${PROJECT_SOURCE_DIR}) +phlex_apply_symbol_visibility(phlex_utilities) + +phlex_make_internal_library( + phlex_utilities + LIBRARIES + PRIVATE Boost::boost + PUBLIC spdlog::spdlog +) +add_library(phlex::utilities_internal ALIAS phlex_utilities_internal) # Interface library cet_make_library( diff --git a/phlex/utilities/hashing.hpp b/phlex/utilities/hashing.hpp index 04b6c045..f521654a 100644 --- a/phlex/utilities/hashing.hpp +++ b/phlex/utilities/hashing.hpp @@ -1,14 +1,17 @@ #ifndef PHLEX_UTILITIES_HASHING_HPP #define PHLEX_UTILITIES_HASHING_HPP +#include "phlex/phlex_utilities_export.hpp" + +#include #include #include namespace phlex::experimental { - std::size_t hash(std::string const& str); - std::size_t hash(std::size_t i) noexcept; - std::size_t hash(std::size_t i, std::size_t j); - std::size_t hash(std::size_t i, std::string const& str); + phlex_utilities_EXPORT std::size_t hash(std::string const& str); + phlex_utilities_EXPORT std::size_t hash(std::size_t i) noexcept; + phlex_utilities_EXPORT std::size_t hash(std::size_t i, std::size_t j); + phlex_utilities_EXPORT std::size_t hash(std::size_t i, std::string const& str); template std::size_t hash(std::size_t i, std::size_t j, Ts... ks) { diff --git a/phlex/utilities/resource_usage.hpp b/phlex/utilities/resource_usage.hpp index f79f4b4c..d7b4e5b7 100644 --- a/phlex/utilities/resource_usage.hpp +++ b/phlex/utilities/resource_usage.hpp @@ -6,10 +6,12 @@ // resource_usage object. The destructor will also report the maximum RSS of the process. // ======================================================================================= +#include "phlex/phlex_utilities_export.hpp" + #include namespace phlex::experimental { - class resource_usage { + class phlex_utilities_EXPORT resource_usage { public: resource_usage() noexcept; ~resource_usage(); diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 63a32a9e..07a0ec3d 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -8,6 +8,12 @@ target_link_libraries(layer_generator PRIVATE phlex::core) install(TARGETS layer_generator LIBRARY) +# Companion library that links against phlex_core_internal so that tests +# using layer_generator do not mix the visibility-hidden and all-visible +# variants of phlex_core in the same process. +add_library(layer_generator_internal layer_generator.cpp) +target_link_libraries(layer_generator_internal PRIVATE phlex_core_internal) + add_library(generate_layers MODULE generate_layers.cpp) target_link_libraries(generate_layers PRIVATE phlex::module layer_generator) diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index b1a29f02..10e30886 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -5,24 +5,24 @@ include(CetTest) cet_test_env(SPDLOG_LEVEL=debug) -cet_test(concepts SOURCE concepts.cpp LIBRARIES phlex::core) +cet_test(concepts SOURCE concepts.cpp LIBRARIES phlex::core_internal) cet_test( adjust_config USE_CATCH2_MAIN SOURCE adjust_config.cpp LIBRARIES - run_phlex + run_phlex_internal Boost::json ) cet_test(config_test USE_CATCH2_MAIN SOURCE configuration.cpp LIBRARIES phlex::configuration ) -cet_test(string_literal SOURCE string_literal.cpp LIBRARIES phlex::utilities) +cet_test(string_literal SOURCE string_literal.cpp LIBRARIES phlex::utilities_internal) cet_test(type_deduction SOURCE type_deduction.cpp LIBRARIES phlex::metaprogramming ) -cet_test(type_id USE_CATCH2_MAIN SOURCE type_id.cpp LIBRARIES phlex::model fmt::fmt) +cet_test(type_id USE_CATCH2_MAIN SOURCE type_id.cpp LIBRARIES phlex::model_internal fmt::fmt) cet_test(identifier USE_CATCH2_MAIN SOURCE identifier.cpp LIBRARIES phlex::model phlex::configuration Boost::json) cet_test( yielding_driver @@ -30,7 +30,7 @@ cet_test( SOURCE yielding_driver.cpp LIBRARIES - phlex::core + phlex::core_internal TBB::tbb ) @@ -40,9 +40,9 @@ cet_test( SOURCE allowed_families.cpp LIBRARIES - phlex::core + phlex::core_internal Boost::json - layer_generator + layer_generator_internal ) cet_test( vector_of_abstract_types @@ -50,8 +50,8 @@ cet_test( SOURCE vector_of_abstract_types.cpp LIBRARIES - phlex::core - layer_generator + phlex::core_internal + layer_generator_internal ) cet_test( cached_execution @@ -59,9 +59,9 @@ cet_test( SOURCE cached_execution.cpp LIBRARIES - phlex::core + phlex::core_internal Boost::json - layer_generator + layer_generator_internal ) cet_test( class_registration @@ -69,7 +69,7 @@ cet_test( SOURCE class_registration.cpp LIBRARIES - phlex::core + phlex::core_internal Boost::json ) cet_test( @@ -78,12 +78,12 @@ cet_test( SOURCE different_hierarchies.cpp LIBRARIES - phlex::core + phlex::core_internal spdlog::spdlog - layer_generator + layer_generator_internal ) cet_test(filter_impl USE_CATCH2_MAIN SOURCE filter_impl.cpp LIBRARIES - phlex::core + phlex::core_internal ) cet_test( filter @@ -91,7 +91,7 @@ cet_test( SOURCE filter.cpp LIBRARIES - phlex::core + phlex::core_internal Boost::json ) cet_test( @@ -100,9 +100,9 @@ cet_test( SOURCE framework_graph.cpp LIBRARIES - phlex::core + phlex::core_internal Boost::json - layer_generator + layer_generator_internal ) cet_test( function_registration @@ -110,7 +110,7 @@ cet_test( SOURCE function_registration.cpp LIBRARIES - phlex::core + phlex::core_internal Boost::json ) cet_test( @@ -121,9 +121,9 @@ cet_test( LIBRARIES Boost::json TBB::tbb - phlex::core + phlex::core_internal spdlog::spdlog - layer_generator + layer_generator_internal ) cet_test( layer_generator_test @@ -131,8 +131,8 @@ cet_test( SOURCE layer_generator.cpp LIBRARIES - phlex::core - layer_generator + phlex::core_internal + layer_generator_internal ) cet_test( multiple_function_registration @@ -141,13 +141,13 @@ cet_test( multiple_function_registration.cpp LIBRARIES Boost::json - phlex::core + phlex::core_internal ) cet_test( output_products USE_CATCH2_MAIN SOURCE output_products.cpp - LIBRARIES layer_generator phlex::core spdlog::spdlog + LIBRARIES layer_generator_internal phlex::core_internal spdlog::spdlog ) cet_test( data_cell_counting @@ -155,20 +155,20 @@ cet_test( SOURCE data_cell_counting.cpp LIBRARIES - phlex::model - phlex::utilities + phlex::model_internal + phlex::utilities_internal ) cet_test(data_cell_index USE_CATCH2_MAIN SOURCE data_cell_index.cpp LIBRARIES - phlex::model + phlex::model_internal ) cet_test(product_handle USE_CATCH2_MAIN SOURCE product_handle.cpp LIBRARIES - phlex::core + phlex::core_internal ) cet_test(product_matcher USE_CATCH2_MAIN SOURCE product_matcher.cpp LIBRARIES - phlex::model + phlex::model_internal ) cet_test(product_store USE_CATCH2_MAIN SOURCE product_store.cpp LIBRARIES - phlex::core + phlex::core_internal ) cet_test( fold @@ -176,9 +176,9 @@ cet_test( SOURCE fold.cpp LIBRARIES - phlex::core + phlex::core_internal spdlog::spdlog - layer_generator + layer_generator_internal ) cet_test( repeater_node @@ -186,7 +186,7 @@ cet_test( SOURCE repeater_node_test.cpp LIBRARIES - phlex::core + phlex::core_internal ) cet_test( replicated @@ -195,15 +195,15 @@ cet_test( replicated.cpp LIBRARIES TBB::tbb - phlex::utilities + phlex::utilities_internal spdlog::spdlog ) cet_test(product_query USE_CATCH2_MAIN SOURCE product_query.cpp LIBRARIES - phlex::core + phlex::core_internal ) cet_test(core_misc_test USE_CATCH2_MAIN SOURCE core_misc_test.cpp LIBRARIES - phlex::core + phlex::core_internal Boost::json ) cet_test( @@ -212,8 +212,8 @@ cet_test( SOURCE provider_test.cpp LIBRARIES - phlex::core - layer_generator + phlex::core_internal + layer_generator_internal ) cet_test( type_distinction @@ -222,7 +222,7 @@ cet_test( type_distinction.cpp LIBRARIES spdlog::spdlog - phlex::core + phlex::core_internal ) cet_test( unfold @@ -231,10 +231,10 @@ cet_test( unfold.cpp LIBRARIES Boost::json - phlex::core + phlex::core_internal TBB::tbb spdlog::spdlog - layer_generator + layer_generator_internal ) add_subdirectory(benchmarks) diff --git a/test/utilities/CMakeLists.txt b/test/utilities/CMakeLists.txt index 9cfd780a..9ace0e04 100644 --- a/test/utilities/CMakeLists.txt +++ b/test/utilities/CMakeLists.txt @@ -1,7 +1,7 @@ -cet_test(sized_tuple SOURCE sized_tuple.cpp LIBRARIES phlex::utilities) +cet_test(sized_tuple SOURCE sized_tuple.cpp LIBRARIES phlex::utilities_internal) cet_test(sleep_for USE_CATCH2_MAIN SOURCE sleep_for.cpp LIBRARIES - phlex::utilities + phlex::utilities_internal ) cet_test( thread_counter @@ -9,6 +9,6 @@ cet_test( SOURCE thread_counter.cpp LIBRARIES - phlex::utilities + phlex::utilities_internal TBB::tbb ) From 67d4b96a772771d1cb0093698fe46f278dd27d4d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Tue, 10 Mar 2026 16:21:22 +0000 Subject: [PATCH 3/4] Add PHLEX_HIDE_SYMBOLS option to toggle symbol visibility mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Introduce option(PHLEX_HIDE_SYMBOLS ... ON) in CMakeLists.txt and wire it through both functions in PhlexSymbolVisibility.cmake: phlex_apply_symbol_visibility(target) ON (default): generate export header + CXX_VISIBILITY_PRESET hidden OFF: generate export header only; all symbols visible by default phlex_make_internal_library(target LIBRARIES ...) ON (default): compile separate SHARED lib with full symbol visibility OFF: create a thin INTERFACE target wrapping the public lib; no extra compilation or .so needed since the public lib already exports everything In OFF mode _internal aliases and layer_generator_internal still exist and link correctly via the INTERFACE wrappers, so no other files change. Benchmark tests (test/benchmarks/, test/max-parallelism/) already link exclusively to curated public targets in both modes. Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Make layer_generator_internal conditional on PHLEX_HIDE_SYMBOLS When PHLEX_HIDE_SYMBOLS=OFF, layer_generator already exports all symbols, so compiling a separate .so for layer_generator_internal is unnecessary. Use a thin INTERFACE alias instead, matching the behaviour of phlex_make_internal_library() for the core libraries. All plugins used by the benchmark tests (test/benchmarks/, test/max-parallelism/) already link exclusively against curated public targets (phlex::module, phlex::core, layer_generator), not the _internal variants. This is unaffected by PHLEX_HIDE_SYMBOLS. Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Add PhlexOptimization.cmake: -fno-semantic-interposition, -fno-plt, PHLEX_ENABLE_IPO The three optimizations are chosen specifically for the symbol-hiding + external-plugin architecture: 1. -fno-semantic-interposition (GCC >= 9, Clang >= 8; when PHLEX_HIDE_SYMBOLS=ON) Allows the compiler to inline, devirtualise, and generate direct (non-PLT) calls for same-DSO accesses to exported functions. Safe only once the exported-symbol surface is explicitly bounded by export macros — exactly what PHLEX_HIDE_SYMBOLS=ON provides. 2. -fno-plt (GCC >= 7.3, Clang >= 4, ELF/Linux only) Replaces PLT stubs with GOT-based dispatch for calls FROM a Phlex library TO external DSOs (TBB, Boost, spdlog, ...). Removes one level of indirection from every cross-DSO call after load-time resolution. 3. PHLEX_ENABLE_IPO (default OFF) Sets CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE and _RELWITHDEBINFO after confirming compiler support. LTO is safe with symbol hiding because export attributes preserve the complete exported-symbol set; the linker cannot eliminate or rename any default-visibility symbol. External plugins compiled without LTO are unaffected. Intentionally excluded: -ffast-math/-funsafe-math-optimizations, which can silently break floating-point correctness in physics/numerical code. PhlexOptimization.cmake is included from the root CMakeLists.txt. phlex_apply_optimizations() is called after phlex_apply_symbol_visibility() in each of the five shared library CMakeLists.txt files. Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Auto-enable PHLEX_ENABLE_IPO for Release/RelWithDebInfo build types cmake -DCMAKE_BUILD_TYPE=Release now automatically opts into LTO without requiring a separate -DPHLEX_ENABLE_IPO=ON. The default is derived from CMAKE_BUILD_TYPE at first configure time: Release / RelWithDebInfo → PHLEX_ENABLE_IPO defaults to ON Debug / Coverage / sanitizer builds → PHLEX_ENABLE_IPO defaults to OFF Multi-config generators (no CMAKE_BUILD_TYPE) → defaults to OFF The option can always be overridden explicitly with -DPHLEX_ENABLE_IPO=ON|OFF. The compile-level flags (-fno-semantic-interposition, -fno-plt) are unchanged: they are applied unconditionally (subject to compiler/platform support) regardless of build type, complementing CMake's per-config CMAKE_CXX_FLAGS_RELEASE (-O3 -DNDEBUG) without duplicating it. Documentation in the module header is updated to describe the full build-type interaction. Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Default PHLEX_HIDE_SYMBOLS based on CMAKE_BUILD_TYPE Mirror the PHLEX_ENABLE_IPO pattern: for Release/RelWithDebInfo builds, default PHLEX_HIDE_SYMBOLS=ON (curated API + -fno-semantic-interposition safe); for Debug, Coverage, and sanitizer builds, default OFF so all symbols are visible to debuggers, profilers, and sanitizer stack traces. cmake -DCMAKE_BUILD_TYPE=Release → PHLEX_HIDE_SYMBOLS=ON, PHLEX_ENABLE_IPO=ON cmake -DCMAKE_BUILD_TYPE=Debug → PHLEX_HIDE_SYMBOLS=OFF, PHLEX_ENABLE_IPO=OFF cmake (no CMAKE_BUILD_TYPE) → both OFF (conservative fallback) Both options can still be overridden explicitly at any time. Update PhlexOptimization.cmake header to document the combined interaction of both options with CMAKE_BUILD_TYPE. Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Auto-adjust PHLEX_HIDE_SYMBOLS default when PHLEX_ENABLE_IPO=ON Move PHLEX_HIDE_SYMBOLS from CMakeLists.txt into PhlexOptimization.cmake so both options are co-located and their defaults are derived together. PHLEX_ENABLE_IPO is now defined first; PHLEX_HIDE_SYMBOLS defaults to ON whenever PHLEX_ENABLE_IPO=ON (in addition to Release/RelWithDebInfo): cmake -DPHLEX_ENABLE_IPO=ON → PHLEX_HIDE_SYMBOLS defaults ON cmake -DCMAKE_BUILD_TYPE=Release → both default ON (unchanged) cmake (Debug / no type) → both default OFF (unchanged) LTO achieves its full potential only with hidden symbols: without -fvisibility=hidden the LTO optimizer must treat every exported symbol as interposable and cannot apply -fno-semantic-interposition. Making IPO automatically pull in symbol hiding as its default ensures the optimal combination is selected whenever LTO is requested. The per-target compile flags in phlex_apply_optimizations() are unchanged: they already self-adjust at build time based on the final option values. The note emitted when a user explicitly overrides PHLEX_HIDE_SYMBOLS=OFF after requesting IPO is retained (now factual rather than advisory). Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Force PHLEX_HIDE_SYMBOLS=ON when PHLEX_ENABLE_IPO=ON (not just default) option() only sets the cache default when the variable is not yet present, so an explicit -DPHLEX_HIDE_SYMBOLS=OFF on the command line bypassed the defaulting logic and produced the invalid combination in CMakeCache.txt. Fix: after both options are resolved from the cache, check for the PHLEX_ENABLE_IPO=ON + PHLEX_HIDE_SYMBOLS=OFF combination and use set(... FORCE) to correct PHLEX_HIDE_SYMBOLS to ON. A STATUS message explains the forced correction. CMakeCache.txt will now always show PHLEX_HIDE_SYMBOLS=ON when PHLEX_ENABLE_IPO=ON. Before: cmake ... -DPHLEX_HIDE_SYMBOLS=OFF -DCMAKE_BUILD_TYPE=Release → CMakeCache.txt: PHLEX_ENABLE_IPO=ON, PHLEX_HIDE_SYMBOLS=OFF ✗ After: cmake ... -DPHLEX_HIDE_SYMBOLS=OFF -DCMAKE_BUILD_TYPE=Release → STATUS "PHLEX_HIDE_SYMBOLS forced ON because PHLEX_ENABLE_IPO=ON" → CMakeCache.txt: PHLEX_ENABLE_IPO=ON, PHLEX_HIDE_SYMBOLS=ON ✓ Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> Revert forced PHLEX_HIDE_SYMBOLS correction; make options fully independent Revert the set(FORCE) that prevented PHLEX_ENABLE_IPO=ON + PHLEX_HIDE_SYMBOLS=OFF: this combination is valid and essential for benchmarking the LTO benefit with and without symbol hiding. All four combinations are now fully supported: PHLEX_HIDE_SYMBOLS=ON PHLEX_ENABLE_IPO=ON → LTO + -fno-semantic-interposition (maximum) PHLEX_HIDE_SYMBOLS=OFF PHLEX_ENABLE_IPO=ON → LTO only (benchmark comparison case) PHLEX_HIDE_SYMBOLS=ON PHLEX_ENABLE_IPO=OFF → -fno-semantic-interposition only PHLEX_HIDE_SYMBOLS=OFF PHLEX_ENABLE_IPO=OFF → no special flags (debug/default) Both options now default independently from CMAKE_BUILD_TYPE (ON for Release/RelWithDebInfo, OFF otherwise) with no cross-dependency in the defaulting logic. The per-target flags in phlex_apply_optimizations() already self-adjust correctly to whichever combination is in effect. Co-authored-by: greenc-FNAL <2372949+greenc-FNAL@users.noreply.github.com> --- CMakeLists.txt | 1 + Modules/private/PhlexOptimization.cmake | 175 ++++++++++++++++++++ Modules/private/PhlexSymbolVisibility.cmake | 37 +++-- phlex/CMakeLists.txt | 1 + phlex/app/CMakeLists.txt | 1 + phlex/core/CMakeLists.txt | 1 + phlex/model/CMakeLists.txt | 1 + phlex/utilities/CMakeLists.txt | 1 + plugins/CMakeLists.txt | 18 +- 9 files changed, 221 insertions(+), 15 deletions(-) create mode 100644 Modules/private/PhlexOptimization.cmake diff --git a/CMakeLists.txt b/CMakeLists.txt index c67482ad..6ca459c0 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -59,6 +59,7 @@ FetchContent_MakeAvailable(Catch2 GSL mimicpp) include(Modules/private/CreateCoverageTargets.cmake) include(Modules/private/PhlexSymbolVisibility.cmake) +include(Modules/private/PhlexOptimization.cmake) option(ENABLE_TSAN "Enable Thread Sanitizer" OFF) option(ENABLE_ASAN "Enable Address Sanitizer" OFF) diff --git a/Modules/private/PhlexOptimization.cmake b/Modules/private/PhlexOptimization.cmake new file mode 100644 index 00000000..a0528d7d --- /dev/null +++ b/Modules/private/PhlexOptimization.cmake @@ -0,0 +1,175 @@ +# Provides phlex_apply_optimizations(target), which applies safe, +# performance-oriented compiler flags to a Phlex shared library target. +# Also defines the PHLEX_HIDE_SYMBOLS and PHLEX_ENABLE_IPO options and +# documents how they interact. +# +# Two flags are applied (subject to compiler support and platform): +# +# -fno-semantic-interposition (GCC >= 9, Clang >= 8) +# The compiler may assume that exported symbols in this shared library are +# not overridden at runtime by LD_PRELOAD or another DSO. This is the +# natural complement of -fvisibility=hidden: once the exported-symbol +# surface is bounded by explicit export macros, treating those symbols as +# non-interposable allows the compiler to inline, devirtualise, and +# generate direct (non-PLT) calls for same-DSO accesses to exported +# functions. +# +# External plugins continue to call Phlex symbols through the standard +# PLT/GOT mechanism; only code compiled as part of a Phlex shared library +# itself benefits. +# +# Applied only when PHLEX_HIDE_SYMBOLS=ON (export macros are present and +# the exported-symbol set is well-defined). +# +# -fno-plt (GCC >= 7.3, Clang >= 4, ELF platforms) +# Calls FROM a Phlex library TO symbols in other shared libraries (TBB, +# Boost, spdlog, ...) bypass the PLT stub and load the target address +# directly from the GOT. This replaces one level of indirection on every +# cross-DSO call after first resolution. Semantics are unchanged; only +# the dispatch mechanism differs. +# +# Not applied on Apple platforms: Mach-O uses two-level namespaces and the +# PLT abstraction does not map directly to ELF semantics. +# +# Intentionally excluded: +# -ffast-math / -funsafe-math-optimizations +# Physics and numerical code relies on well-defined floating-point +# semantics (NaN propagation, exact rounding, signed-zero behaviour). +# These flags may silently produce incorrect numerical results and are +# therefore not enabled. +# +# Options and their interaction with CMAKE_BUILD_TYPE +# +# Both PHLEX_HIDE_SYMBOLS and PHLEX_ENABLE_IPO are defined here so that their +# defaults can be derived together. The effective defaults are: +# +# CMAKE_BUILD_TYPE PHLEX_ENABLE_IPO PHLEX_HIDE_SYMBOLS +# ───────────────── ─────────────── ───────────────── +# Release ON ON +# RelWithDebInfo ON ON +# Debug / sanitizer OFF OFF +# not set OFF OFF +# +# Both options can be overridden independently on the command line: +# +# -DPHLEX_HIDE_SYMBOLS=ON -DPHLEX_ENABLE_IPO=ON → LTO + -fno-semantic-interposition +# (maximum optimization) +# -DPHLEX_HIDE_SYMBOLS=OFF -DPHLEX_ENABLE_IPO=ON → LTO only; -fno-semantic-interposition +# is NOT applied (valid, useful for +# benchmarking against the ON case) +# -DPHLEX_HIDE_SYMBOLS=ON -DPHLEX_ENABLE_IPO=OFF → -fno-semantic-interposition only +# -DPHLEX_HIDE_SYMBOLS=OFF -DPHLEX_ENABLE_IPO=OFF → no special optimization flags +# +# The per-target flags in phlex_apply_optimizations() self-adjust automatically +# to reflect whichever combination is in effect. +# +# PHLEX_ENABLE_IPO (default ON for Release/RelWithDebInfo, OFF otherwise) +# When ON, enables interprocedural optimization (LTO) for Release and +# RelWithDebInfo configurations. LTO is safe with or without symbol hiding +# because export attributes preserve the complete exported-symbol set. +# External plugins compiled without LTO link against the normal +# exported-symbol table and are unaffected. +# +# PHLEX_HIDE_SYMBOLS (default ON for Release/RelWithDebInfo, OFF otherwise) +# When ON: hidden-by-default visibility; export macros mark the public API. +# When OFF: all symbols visible; _internal targets become thin INTERFACE +# aliases of their public counterparts. + + +include_guard() + +include(CheckCXXCompilerFlag) + +# Probe flag availability once at module-load time (results are cached in the +# CMake cache and reused across reconfigures). +check_cxx_compiler_flag( + "-fno-semantic-interposition" + PHLEX_CXX_HAVE_NO_SEMANTIC_INTERPOSITION +) + +if(NOT APPLE) + check_cxx_compiler_flag("-fno-plt" PHLEX_CXX_HAVE_NO_PLT) +endif() + +# --------------------------------------------------------------------------- +# Interprocedural optimization (LTO) — defined first so its value can inform +# the PHLEX_HIDE_SYMBOLS default below. +# --------------------------------------------------------------------------- +cmake_policy(SET CMP0069 NEW) +include(CheckIPOSupported) + +if(CMAKE_BUILD_TYPE MATCHES "^(Release|RelWithDebInfo)$") + set(_phlex_ipo_default ON) +else() + set(_phlex_ipo_default OFF) +endif() + +option( + PHLEX_ENABLE_IPO + [=[Enable interprocedural optimization (LTO) for Release and RelWithDebInfo +builds. Defaults to ON when CMAKE_BUILD_TYPE is Release or RelWithDebInfo. +Can be combined with PHLEX_HIDE_SYMBOLS=ON for maximum optimization, or with +PHLEX_HIDE_SYMBOLS=OFF to benchmark LTO benefit without symbol hiding.]=] + "${_phlex_ipo_default}" +) + +# --------------------------------------------------------------------------- +# Symbol hiding — default follows CMAKE_BUILD_TYPE independently of IPO. +# The two options are orthogonal: both ON/OFF combinations are valid and +# produce different optimization profiles for benchmarking. +# --------------------------------------------------------------------------- +if(CMAKE_BUILD_TYPE MATCHES "^(Release|RelWithDebInfo)$") + set(_phlex_hide_default ON) +else() + set(_phlex_hide_default OFF) +endif() + +option( + PHLEX_HIDE_SYMBOLS + [=[Hide non-exported symbols in shared libraries (ON = curated API with +hidden-by-default visibility; OFF = all symbols visible). Defaults to ON for +Release/RelWithDebInfo builds. +Combined with PHLEX_ENABLE_IPO=ON: -fno-semantic-interposition is also applied +for maximum optimization. Setting OFF while PHLEX_ENABLE_IPO=ON is valid and +useful for comparing LTO performance with and without symbol hiding.]=] + "${_phlex_hide_default}" +) + +# --------------------------------------------------------------------------- +# Activate LTO (if enabled and supported) +# --------------------------------------------------------------------------- +if(PHLEX_ENABLE_IPO) + check_ipo_supported( + RESULT _phlex_ipo_supported + OUTPUT _phlex_ipo_output + LANGUAGES CXX + ) + if(_phlex_ipo_supported) + # Set defaults for all targets created in this scope and below. The + # *_RELEASE and *_RELWITHDEBINFO variants leave Debug/Coverage/sanitizer + # builds unaffected (those configs override optimization independently). + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE ON) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) + message(STATUS "Phlex: LTO enabled for Release and RelWithDebInfo builds") + else() + message( + WARNING + "Phlex: PHLEX_ENABLE_IPO=ON but LTO is not supported: ${_phlex_ipo_output}" + ) + endif() +endif() + +# --------------------------------------------------------------------------- +function(phlex_apply_optimizations target) + # -fno-semantic-interposition pairs with PHLEX_HIDE_SYMBOLS: the compiler + # may only treat exported symbols as non-interposable once the exported- + # symbol surface has been explicitly bounded by export macros. + if(PHLEX_HIDE_SYMBOLS AND PHLEX_CXX_HAVE_NO_SEMANTIC_INTERPOSITION) + target_compile_options("${target}" PRIVATE "-fno-semantic-interposition") + endif() + + # -fno-plt reduces cross-DSO call overhead on ELF (Linux) platforms. + if(PHLEX_CXX_HAVE_NO_PLT) + target_compile_options("${target}" PRIVATE "-fno-plt") + endif() +endfunction() diff --git a/Modules/private/PhlexSymbolVisibility.cmake b/Modules/private/PhlexSymbolVisibility.cmake index d2dd906e..69590f45 100644 --- a/Modules/private/PhlexSymbolVisibility.cmake +++ b/Modules/private/PhlexSymbolVisibility.cmake @@ -12,32 +12,49 @@ function(phlex_apply_symbol_visibility target) STATIC_DEFINE "${target}_STATIC_DEFINE" ) - set_target_properties( - ${target} - PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON - ) + if(PHLEX_HIDE_SYMBOLS) + set_target_properties( + ${target} + PROPERTIES CXX_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON + ) + endif() target_include_directories(${target} PUBLIC $) install(FILES "${EXPORT_HEADER}" DESTINATION include/phlex) endfunction() -# Create a non-installed companion library _internal with default (visible) symbol -# visibility for all symbols. This allows tests to access non-exported implementation -# details without requiring every internal symbol to carry an EXPORT macro, and enables +# Create a companion library _internal: +# +# When PHLEX_HIDE_SYMBOLS is ON (default): a non-installed shared library with +# default (visible) symbol visibility, compiled from the same sources as +# . This allows tests to access non-exported implementation details +# without requiring every internal symbol to carry an EXPORT macro, and enables # before/after comparison of library/executable sizes and link/load times. # +# When PHLEX_HIDE_SYMBOLS is OFF: an INTERFACE target that simply links to +# . Since all public library symbols are already visible in this mode, +# no separate compilation is needed and _internal targets are effectively +# identical to their public counterparts. +# # Usage (in the same CMakeLists.txt that defines ): # phlex_make_internal_library( LIBRARIES [PUBLIC ...] [PRIVATE ...]) # -# The LIBRARIES arguments mirror those of the original cet_make_library call but may -# substitute other _internal targets for the corresponding public ones so that the -# full transitive symbol set is visible. +# The LIBRARIES arguments mirror those of the original cet_make_library call but +# may substitute other _internal targets for the corresponding public ones so +# that the full transitive symbol set is visible (PHLEX_HIDE_SYMBOLS=ON only). function(phlex_make_internal_library target) cmake_parse_arguments(ARG "" "" "LIBRARIES" ${ARGN}) set(internal "${target}_internal") + if(NOT PHLEX_HIDE_SYMBOLS) + # All public symbols already visible — _internal is a thin INTERFACE wrapper. + add_library(${internal} INTERFACE) + target_link_libraries(${internal} INTERFACE ${target}) + return() + endif() + # Retrieve sources and source directory from the public target so we don't # have to maintain a separate source list. get_target_property(srcs ${target} SOURCES) diff --git a/phlex/CMakeLists.txt b/phlex/CMakeLists.txt index e81b7002..76e54ae2 100644 --- a/phlex/CMakeLists.txt +++ b/phlex/CMakeLists.txt @@ -34,6 +34,7 @@ cet_make_library( phlex::core ) phlex_apply_symbol_visibility(phlex_configuration_internal) +phlex_apply_optimizations(phlex_configuration_internal) cet_make_library( LIBRARY_NAME diff --git a/phlex/app/CMakeLists.txt b/phlex/app/CMakeLists.txt index 42ccc9ca..66c53749 100644 --- a/phlex/app/CMakeLists.txt +++ b/phlex/app/CMakeLists.txt @@ -19,6 +19,7 @@ cet_make_library( install(FILES load_module.hpp run.hpp version.hpp DESTINATION include/phlex/app) phlex_apply_symbol_visibility(run_phlex) +phlex_apply_optimizations(run_phlex) # We'll use C++17's filesystem instead of Boost's target_compile_definitions(run_phlex PRIVATE BOOST_DLL_USE_STD_FS) diff --git a/phlex/core/CMakeLists.txt b/phlex/core/CMakeLists.txt index 6e31ad98..fce6340f 100644 --- a/phlex/core/CMakeLists.txt +++ b/phlex/core/CMakeLists.txt @@ -82,6 +82,7 @@ install( ) target_include_directories(phlex_core PRIVATE ${PROJECT_SOURCE_DIR}) phlex_apply_symbol_visibility(phlex_core) +phlex_apply_optimizations(phlex_core) # AppleClang 15.0 still treats std::views::join as experimental if( diff --git a/phlex/model/CMakeLists.txt b/phlex/model/CMakeLists.txt index 3209bf43..f75e21f7 100644 --- a/phlex/model/CMakeLists.txt +++ b/phlex/model/CMakeLists.txt @@ -41,6 +41,7 @@ install( target_include_directories(phlex_model PRIVATE ${PROJECT_SOURCE_DIR}) phlex_apply_symbol_visibility(phlex_model) +phlex_apply_optimizations(phlex_model) phlex_make_internal_library( phlex_model diff --git a/phlex/utilities/CMakeLists.txt b/phlex/utilities/CMakeLists.txt index def3a769..5edf24c7 100644 --- a/phlex/utilities/CMakeLists.txt +++ b/phlex/utilities/CMakeLists.txt @@ -28,6 +28,7 @@ install( target_include_directories(phlex_utilities PRIVATE ${PROJECT_SOURCE_DIR}) phlex_apply_symbol_visibility(phlex_utilities) +phlex_apply_optimizations(phlex_utilities) phlex_make_internal_library( phlex_utilities diff --git a/plugins/CMakeLists.txt b/plugins/CMakeLists.txt index 07a0ec3d..8f14921e 100644 --- a/plugins/CMakeLists.txt +++ b/plugins/CMakeLists.txt @@ -8,11 +8,19 @@ target_link_libraries(layer_generator PRIVATE phlex::core) install(TARGETS layer_generator LIBRARY) -# Companion library that links against phlex_core_internal so that tests -# using layer_generator do not mix the visibility-hidden and all-visible -# variants of phlex_core in the same process. -add_library(layer_generator_internal layer_generator.cpp) -target_link_libraries(layer_generator_internal PRIVATE phlex_core_internal) +# Companion library for tests. +# PHLEX_HIDE_SYMBOLS=ON: separate compile against phlex_core_internal so that +# tests linking it do not mix the visibility-hidden and all-visible variants +# of phlex_core in the same process. +# PHLEX_HIDE_SYMBOLS=OFF: thin INTERFACE alias — layer_generator already +# exports all symbols, so no separate .so is needed. +if(PHLEX_HIDE_SYMBOLS) + add_library(layer_generator_internal layer_generator.cpp) + target_link_libraries(layer_generator_internal PRIVATE phlex_core_internal) +else() + add_library(layer_generator_internal INTERFACE) + target_link_libraries(layer_generator_internal INTERFACE layer_generator) +endif() add_library(generate_layers MODULE generate_layers.cpp) target_link_libraries(generate_layers PRIVATE phlex::module layer_generator) From c63bd453125a52aad214cd30318e22a61c48f076 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Fri, 13 Mar 2026 15:57:55 +0000 Subject: [PATCH 4/4] Apply cmake-format fixes --- Modules/private/PhlexOptimization.cmake | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/Modules/private/PhlexOptimization.cmake b/Modules/private/PhlexOptimization.cmake index a0528d7d..1f8ad1dd 100644 --- a/Modules/private/PhlexOptimization.cmake +++ b/Modules/private/PhlexOptimization.cmake @@ -75,17 +75,13 @@ # When OFF: all symbols visible; _internal targets become thin INTERFACE # aliases of their public counterparts. - include_guard() include(CheckCXXCompilerFlag) # Probe flag availability once at module-load time (results are cached in the # CMake cache and reused across reconfigures). -check_cxx_compiler_flag( - "-fno-semantic-interposition" - PHLEX_CXX_HAVE_NO_SEMANTIC_INTERPOSITION -) +check_cxx_compiler_flag("-fno-semantic-interposition" PHLEX_CXX_HAVE_NO_SEMANTIC_INTERPOSITION) if(NOT APPLE) check_cxx_compiler_flag("-fno-plt" PHLEX_CXX_HAVE_NO_PLT) @@ -139,11 +135,7 @@ useful for comparing LTO performance with and without symbol hiding.]=] # Activate LTO (if enabled and supported) # --------------------------------------------------------------------------- if(PHLEX_ENABLE_IPO) - check_ipo_supported( - RESULT _phlex_ipo_supported - OUTPUT _phlex_ipo_output - LANGUAGES CXX - ) + check_ipo_supported(RESULT _phlex_ipo_supported OUTPUT _phlex_ipo_output LANGUAGES CXX) if(_phlex_ipo_supported) # Set defaults for all targets created in this scope and below. The # *_RELEASE and *_RELWITHDEBINFO variants leave Debug/Coverage/sanitizer @@ -152,10 +144,7 @@ if(PHLEX_ENABLE_IPO) set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELWITHDEBINFO ON) message(STATUS "Phlex: LTO enabled for Release and RelWithDebInfo builds") else() - message( - WARNING - "Phlex: PHLEX_ENABLE_IPO=ON but LTO is not supported: ${_phlex_ipo_output}" - ) + message(WARNING "Phlex: PHLEX_ENABLE_IPO=ON but LTO is not supported: ${_phlex_ipo_output}") endif() endif()