Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ endif()
###################

include( ${CMAKE_CURRENT_LIST_DIR}/functionoid.cmake )
include( ${CMAKE_CURRENT_LIST_DIR}/module.cmake )

###################
## Tests
Expand Down
91 changes: 91 additions & 0 deletions module.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Optional C++20 named module support for psi::functionoid (opt-in, off by default).
#
# Adds a target, `PsiFunctionoidModule` (alias `Psi::FunctionoidModule`), exporting every
# functionoid public header as `import psi.functionoid;` instead of textual `#include`. Purely
# additive: PsiFunctionoid (the existing header-only INTERFACE target) is untouched, so any
# consumer vendoring these headers directly is unaffected regardless of whether this option exists.
#
# Shape: matches psiha/vm's own module.cmake (feat/module-support there) - the global module
# fragment carries the STL plus the two macro-only psiha deps these headers use (boost/assert.hpp,
# boost/config_ex.hpp) textually, since modules never export macros; a consumer wanting
# BOOST_ASSERT after `import psi.functionoid;` still includes boost/assert.hpp itself. The purview
# (`export extern "C++"`) carries every real header via file(GLOB_RECURSE), so a header added
# later is picked up automatically.
#
# Toolchain: clang-cl and the GNU-driver clang only (see psiha/vm's module.cmake for why); MSVC
# and GCC are left alone, a warning rather than a hard error when the option is set there anyway.

option( PSI_FUNCTIONOID_MODULE "Build psi.functionoid as a C++20 named module (opt-in; requires clang-cl or clang)" OFF )

if ( PSI_FUNCTIONOID_MODULE )
if ( NOT ( CMAKE_CXX_COMPILER_ID MATCHES Clang ) )
message( WARNING "PSI_FUNCTIONOID_MODULE requires clang-cl or clang; ignored on ${CMAKE_CXX_COMPILER_ID}." )
else()
if ( CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC" )
cmake_path( GET CMAKE_CXX_COMPILER PARENT_PATH _psi_functionoid_llvm_bin )
find_program( PSI_FUNCTIONOID_CLANG_SCAN_DEPS clang-scan-deps HINTS "${_psi_functionoid_llvm_bin}" REQUIRED )
string( CONCAT CMAKE_CXX_SCANDEP_SOURCE
"\"${PSI_FUNCTIONOID_CLANG_SCAN_DEPS}\" -format=p1689 -- <CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS>"
" /TP <SOURCE> /c /Fo<OBJECT> /clang:-MT /clang:<DYNDEP_FILE> /clang:-MD /clang:-MF /clang:<DEP_FILE>"
" > <DYNDEP_FILE>.tmp && \"${CMAKE_COMMAND}\" -E rename <DYNDEP_FILE>.tmp <DYNDEP_FILE>" )
set( CMAKE_CXX_MODULE_MAP_FORMAT clang )
set( CMAKE_CXX_MODULE_MAP_FLAG "@<MODULE_MAP_FILE>" )
set( CMAKE_CXX_COMPILE_BMI "<CMAKE_CXX_COMPILER> <DEFINES> <INCLUDES> <FLAGS> /clang:-o<OBJECT> /clang:--precompile /TP <SOURCE>" )
endif()

file( GLOB_RECURSE psi_functionoid_module_headers RELATIVE "${CMAKE_CURRENT_LIST_DIR}/include" "${CMAKE_CURRENT_LIST_DIR}/include/*.hpp" )

set( _psi_functionoid_module_purview "${CMAKE_CURRENT_BINARY_DIR}/psi_functionoid_module_purview.hpp" )
set( _psi_functionoid_module_content "// Generated by module.cmake - every psi::functionoid public header, cumulative.\n" )
foreach( h ${psi_functionoid_module_headers} )
string( APPEND _psi_functionoid_module_content "#include <${h}>\n" )
endforeach()
file( WRITE "${_psi_functionoid_module_purview}" "${_psi_functionoid_module_content}" )

set( _psi_functionoid_module_unit "${CMAKE_CURRENT_BINARY_DIR}/psi_functionoid_module.cppm" )
file( WRITE "${_psi_functionoid_module_unit}" "\
module;
#if defined( __x86_64__ ) || defined( _M_X64 )
#include <immintrin.h>
#endif
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#define NOMINMAX
#include <windows.h>
#undef ERROR
#endif
#include <algorithm>
#include <array>
#include <bit>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <functional>
#include <memory>
#include <type_traits>
#include <tuple>
#include <utility>
#include <boost/assert.hpp>
#include <boost/config_ex.hpp>
export module psi.functionoid;
export extern \"C++\"
{
#include \"${_psi_functionoid_module_purview}\"
}
" )

add_library( PsiFunctionoidModule STATIC )
add_library( Psi::FunctionoidModule ALIAS PsiFunctionoidModule )
target_compile_features( PsiFunctionoidModule PUBLIC cxx_std_23 )
target_sources( PsiFunctionoidModule PUBLIC FILE_SET CXX_MODULES BASE_DIRS "${CMAKE_CURRENT_BINARY_DIR}" FILES "${_psi_functionoid_module_unit}" )
target_include_directories( PsiFunctionoidModule PUBLIC "${_functionoid_include}" )
if ( TARGET Boost::boost )
target_link_libraries( PsiFunctionoidModule PUBLIC Boost::boost )
endif()
target_compile_options( PsiFunctionoidModule PRIVATE
$<$<CXX_COMPILER_FRONTEND_VARIANT:MSVC>:/clang:-std=gnu++2c /clang:-Wno-include-angled-in-module-purview /clang:-Wno-reserved-module-identifier>
$<$<NOT:$<CXX_COMPILER_FRONTEND_VARIANT:MSVC>>:-Wno-include-angled-in-module-purview -Wno-reserved-module-identifier>
)
endif()
endif()
13 changes: 13 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,16 @@ target_link_libraries( functionoid_vtable_attrs PRIVATE GTest::gtest_main Psi::F

set_target_properties( functionoid_vtable_attrs PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test" )
add_test( NAME functionoid_vtable_attrs COMMAND functionoid_vtable_attrs )

# Module correctness smoke test (module.cmake, PSI_FUNCTIONOID_MODULE) — only built when the
# option is on, so it adds nothing to the default (off) CI matrix.
if ( PSI_FUNCTIONOID_MODULE AND TARGET PsiFunctionoidModule )
add_executable( functionoid_module_smoke_test EXCLUDE_FROM_ALL "${CMAKE_CURRENT_SOURCE_DIR}/module_smoke_test.cpp" )
target_link_libraries( functionoid_module_smoke_test PRIVATE Psi::FunctionoidModule )
set_target_properties( functionoid_module_smoke_test PROPERTIES
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/test"
CXX_SCAN_FOR_MODULES ON
DISABLE_PRECOMPILE_HEADERS ON
)
add_test( NAME functionoid_module_smoke_test COMMAND functionoid_module_smoke_test )
endif()
23 changes: 23 additions & 0 deletions test/module_smoke_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Standalone correctness check for the psi.functionoid module (module.cmake,
// PSI_FUNCTIONOID_MODULE): builds a small executable that only `import`s psi.functionoid and
// exercises real callable<> usage, so a broken module boundary shows up as a build or runtime
// failure here rather than surfacing only downstream in a consumer project.
import psi.functionoid;

#include <boost/assert.hpp>
#include <cstdio>

int main()
{
int captured{ 10 };
psi::functionoid::callable<int()> fn{ [&]() noexcept -> int { return captured + 32; } };
int const result{ fn() };
BOOST_ASSERT( result == 42 );

fn = []() noexcept -> int { return 0; };
int const reassigned{ fn() };

int const sum{ result + reassigned };
std::printf( "%d\n", sum );
return sum == 42 ? 0 : 1;
}
Loading