diff --git a/CMakeLists.txt b/CMakeLists.txt index ff1fe4653..c684617ec 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -16,6 +16,10 @@ if(EMSCRIPTEN) set(CPPINTEROP_EXTRA_WASM_FLAGS "-fwasm-exceptions" CACHE STRING "Extra flags for wasm") endif() +# Clad plugin options +option(CPPINTEROP_ENABLE_CLAD "Enable the Clad automatic differentiation plugin." OFF) +set(CLAD_BUILD_TYPE "Release" CACHE STRING "Build type for clad plugins") + if (CPPINTEROP_USE_CLING AND CPPINTEROP_USE_REPL) message(FATAL_ERROR "We can only use Cling (${CPPINTEROP_USE_CLING}=On) or Repl (CPPINTEROP_USE_REPL=On), but not both of them.") endif() @@ -526,6 +530,12 @@ if (CPPINTEROP_INCLUDE_DOCS) add_subdirectory(docs) endif() +if(CPPINTEROP_ENABLE_CLAD) + message(STATUS "CPPINTEROP_ENABLE_CLAD is ON: Building CppInterOp Clad plugin.") + message(STATUS "Clad build type: ${CLAD_BUILD_TYPE}") + add_subdirectory(plugins/clad) +endif() + add_subdirectory(lib) if (CPPINTEROP_ENABLE_TESTING) add_subdirectory(unittests) diff --git a/lib/CppInterOp/CMakeLists.txt b/lib/CppInterOp/CMakeLists.txt index 44e3c2b8b..19795a19e 100644 --- a/lib/CppInterOp/CMakeLists.txt +++ b/lib/CppInterOp/CMakeLists.txt @@ -104,6 +104,18 @@ if (LLVM_LINK_LLVM_DYLIB) ) endif(LLVM_LINK_LLVM_DYLIB) +if(CPPINTEROP_ENABLE_CLAD) + set(CPPINTEROP_PLUGIN_LINK_LIBS) + if (APPLE) + set(CPPINTEROP_PLUGIN_LINK_LIBS -Wl,-force_load cladPlugin -Wl,-force_load cladDifferentiator) + elseif(MSVC) + set(CPPINTEROP_PLUGIN_LINK_LIBS cladPlugin cladDifferentiator) + set(CLAD_LIBS "-WHOLEARCHIVE:cladPlugin.lib -WHOLEARCHIVE:cladDifferentiator.lib") + else() + set(CPPINTEROP_PLUGIN_LINK_LIBS -Wl,--whole-archive cladPlugin cladDifferentiator -Wl,--no-whole-archive) + endif() +endif(CPPINTEROP_ENABLE_CLAD) + add_llvm_library(clangCppInterOp DISABLE_LLVM_LINK_LLVM_DYLIB CppInterOp.cpp @@ -112,6 +124,7 @@ add_llvm_library(clangCppInterOp ${DLM} LINK_LIBS ${link_libs} + ${CPPINTEROP_PLUGIN_LINK_LIBS} ) if(EMSCRIPTEN) @@ -161,6 +174,12 @@ endif(EMSCRIPTEN) target_compile_definitions(clangCppInterOp PUBLIC "_CINDEX_LIB_") # workaround for the use of `CINDEX_LINKAGE` string(REPLACE ";" "\;" _VER CPPINTEROP_VERSION) -set_source_files_properties(CppInterOp.cpp PROPERTIES COMPILE_DEFINITIONS - "LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\";CPPINTEROP_VERSION=\"${_VAR}\"" +set_property(SOURCE CppInterOp.cpp APPEND PROPERTY COMPILE_DEFINITIONS + "LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\"" + "CPPINTEROP_VERSION=\"${_VAR}\"" ) + +set_property(SOURCE CppInterOp.cpp APPEND PROPERTY COMPILE_DEFINITIONS + "CLAD_INCLUDE_DIRS=\"${CMAKE_BINARY_DIR}/plugins/clad/include/\"" + "CPPINTEROP_ENABLE_CLAD=\"${CPPINTEROP_ENABLE_CLAD}\"" +) \ No newline at end of file diff --git a/lib/CppInterOp/CppInterOp.cpp b/lib/CppInterOp/CppInterOp.cpp index bdeeb5c43..fca0108db 100644 --- a/lib/CppInterOp/CppInterOp.cpp +++ b/lib/CppInterOp/CppInterOp.cpp @@ -3455,6 +3455,9 @@ TInterp_t CreateInterpreter(const std::vector& Args /*={}*/, *I, "__clang_Interpreter_SetValueNoAlloc", reinterpret_cast(&__clang_Interpreter_SetValueNoAlloc)); #endif + if(CPPINTEROP_ENABLE_CLAD) { + Cpp::AddIncludePath(CLAD_INCLUDE_DIRS); + } return I; } diff --git a/plugins/clad/CMakeLists.txt b/plugins/clad/CMakeLists.txt new file mode 100644 index 000000000..27dbb2f8c --- /dev/null +++ b/plugins/clad/CMakeLists.txt @@ -0,0 +1,95 @@ +include(ExternalProject) + +set(clad_install_dir ${CMAKE_BINARY_DIR}/plugins/clad/) +# Specify include dirs for clad +set(CLAD_INCLUDE_DIRS ${clad_install_dir}) +# Clad Libraries +set(CLAD_CXX_FLAGS ${CMAKE_CXX_FLAGS}) +set(_clad_build_type ${CLAD_BUILD_TYPE}) +if(MSVC AND NOT CMAKE_GENERATOR MATCHES Ninja) + if (winrtdebug) + set(_clad_build_type Debug) + else() + set(_clad_build_type Release) + endif() + if(asan) + set(CLAD_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${ASAN_EXTRA_CXX_FLAGS}") + endif() + set(EXTRA_BUILD_ARGS --config ${_clad_build_type}) +endif() +if(NOT _clad_build_type STREQUAL "" AND NOT _clad_build_type STREQUAL ".") + set(EXTRA_BUILD_ARGS --config ${_clad_build_type}) +endif() + +set(_CLAD_LIBRARY_PATH ${CMAKE_CURRENT_BINARY_DIR}/clad-prefix/src/clad-build/lib/) + +# build byproducts only needed by Ninja +if(CMAKE_GENERATOR MATCHES Ninja) + set(CLAD_BYPRODUCTS + ${_CLAD_LIBRARY_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}cladPlugin${CMAKE_STATIC_LIBRARY_SUFFIX} + ${_CLAD_LIBRARY_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}cladDifferentiator${CMAKE_STATIC_LIBRARY_SUFFIX} + ) +endif() + +if(APPLE) + set(_clad_extra_cmake_args -DCMAKE_OSX_SYSROOT=${CMAKE_OSX_SYSROOT}) +endif() + +if (CMAKE_CXX_STANDARD) + list(APPEND _clad_extra_cmake_args -DCMAKE_CXX_STANDARD=${CMAKE_CXX_STANDARD}) +endif(CMAKE_CXX_STANDARD) + +if (LLVM_FORCE_USE_OLD_TOOLCHAIN) + list(APPEND _clad_extra_cmake_args -DLLVM_FORCE_USE_OLD_TOOLCHAIN=${LLVM_FORCE_USE_OLD_TOOLCHAIN}) +endif(LLVM_FORCE_USE_OLD_TOOLCHAIN) + +list(APPEND _clad_extra_cmake_args -DCLAD_BUILD_STATIC_ONLY=ON) + +# Wrap download, configure and build steps in a script to log output +set(_clad_extra_settings + LOG_DOWNLOAD ON + LOG_CONFIGURE ON + LOG_BUILD ON + LOG_INSTALL ON + LOG_OUTPUT_ON_FAILURE ON +) + +if (DEFINED CLAD_SOURCE_DIR) + message(STATUS "Using local clad source directory: ${CLAD_SOURCE_DIR}") + list(APPEND _clad_extra_settings SOURCE_DIR ${CLAD_SOURCE_DIR}) +else() + list(APPEND _clad_extra_settings GIT_REPOSITORY https://github.com/vgvassilev/clad.git) + list(APPEND _clad_extra_settings GIT_TAG v2.2) +endif() + +message(STATUS "CMAKE_COMMAND: ${CMAKE_COMMAND}") +message(STATUS "EXTRA_BUILD_ARGS: ${EXTRA_BUILD_ARGS}") + +ExternalProject_Add( + clad + UPDATE_COMMAND "" + CMAKE_ARGS -G ${CMAKE_GENERATOR} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_COMPILER=${CMAKE_C_COMPILER} + -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER} + -DCMAKE_CXX_FLAGS=${CLAD_CXX_FLAGS} + -DCMAKE_CXX_FLAGS_DEBUG=${CMAKE_CXX_FLAGS_DEBUG} + -DCMAKE_INSTALL_PREFIX=${clad_install_dir} + -DLLVM_DIR=${LLVM_DIR} + -DClang_DIR=${CLANG_CMAKE_DIR} + ${_clad_extra_cmake_args} + BUILD_COMMAND ${CMAKE_COMMAND} --build . ${EXTRA_BUILD_ARGS} --parallel + INSTALL_COMMAND ${CMAKE_COMMAND} --build . ${EXTRA_BUILD_ARGS} --target install + BUILD_BYPRODUCTS ${CLAD_BYPRODUCTS} + ${_clad_extra_settings} + ) + +# Register cladPlugin, cladDifferentiator +foreach (lib cladPlugin cladDifferentiator) + add_library(${lib} IMPORTED STATIC GLOBAL) + add_dependencies(${lib} clad) +endforeach() + +set_property(TARGET cladPlugin PROPERTY IMPORTED_LOCATION ${_CLAD_LIBRARY_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}cladPlugin${CMAKE_STATIC_LIBRARY_SUFFIX}) +set_property(TARGET cladDifferentiator PROPERTY IMPORTED_LOCATION ${_CLAD_LIBRARY_PATH}/${CMAKE_STATIC_LIBRARY_PREFIX}cladDifferentiator${CMAKE_STATIC_LIBRARY_SUFFIX}) diff --git a/unittests/CppInterOp/CMakeLists.txt b/unittests/CppInterOp/CMakeLists.txt index 92ce2fdab..10111b8cc 100644 --- a/unittests/CppInterOp/CMakeLists.txt +++ b/unittests/CppInterOp/CMakeLists.txt @@ -11,8 +11,9 @@ else() endif() add_cppinterop_unittest(CppInterOpTests - ENABLE_DISPATCH + # ENABLE_DISPATCH CommentReflectionTest.cpp + CladTest.cpp EnumReflectionTest.cpp FunctionReflectionTest.cpp InterpreterTest.cpp @@ -33,6 +34,9 @@ endif () set_source_files_properties(InterpreterTest.cpp PROPERTIES COMPILE_DEFINITIONS "LLVM_BINARY_DIR=\"${LLVM_BINARY_DIR}\"" ) +set_source_files_properties(CladTest.cpp PROPERTIES COMPILE_DEFINITIONS + "CLAD_INCLUDE_DIRS=\"${CMAKE_BINARY_DIR}/plugins/clad/include/\"" +) if(EMSCRIPTEN) string(REPLACE "@" "@@" ESCAPED_SYSROOT_PATH "${SYSROOT_PATH}") diff --git a/unittests/CppInterOp/CladTest.cpp b/unittests/CppInterOp/CladTest.cpp new file mode 100644 index 000000000..5212dfa82 --- /dev/null +++ b/unittests/CppInterOp/CladTest.cpp @@ -0,0 +1,32 @@ +#include "Utils.h" + +#include "CppInterOp/CppInterOp.h" +#include "gtest/gtest.h" + +using namespace TestUtils; +using namespace llvm; +using namespace clang; + +// This should work +// TYPED_TEST(CppInterOpTest, CladTestSanity) { +// std::string code = R"( +// #include "CppInterOp/CppInterOp.h" +// )"; + +// auto I = Cpp::CreateInterpreter(); +// Cpp::Declare(code.c_str()); +// } + +TYPED_TEST(CPPINTEROP_TEST_MODE, CladTest_Sanity) { + std::vector Decls; + std::string code = R"( + #include "clad/Differentiator/Differentiator.h" + static double pow2(double x) { return x * x; } + )"; + + auto I = Cpp::CreateInterpreter({"-std=c++17"}, {}); + Cpp::Declare(code.c_str() DFLT_FALSE); + + std::string code_diff = "clad::differentiate(pow2, 0).execute(3)"; + ASSERT_EQ(Cpp::Evaluate(code_diff.c_str() DFLT_NULLPTR), 6); +}