I am using the ISPC to compile .ispc files and link them to my C++ project using CMake. A quirk of the ISPC is that it generates the header files that are to be included by the C++ code. For ease of building it, all of my ISPC files are in one static library. The core of my C++ code is in a static library that depends on the ISPC library. Finally, my project executable is a separate project, and it links against the core C++ code (this is for unit testing, but that's irrelevant here).
Here is my file structure:
src/
|
+ core/
| |
| +--CMakeLists.txt
| +--core_code.cpp
| |
| + ispc/
| |
| +--CmakeLists.txt
| +--simd_code.ispc
|
+ runner/
|
+--CMakeLists.txt
+--main.cpp
The relevant parts of my CMakeLists files are as follows
# src/CMakeList.txt
add_subdirectory(core)
add_subdirectory(runner)
# src/core/CMakeLists.txt
add_library(CoreLib STATIC)
target_sources(CoreLib PUBLIC core_code.cpp)
# Add ISPC dependent code
add_subdirectory(ispc)
target_link_libraries(CoreLib PUBLIC IspcLib)
target_include_directories(CoreLib PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>
)
# I believe I need to specify another include dirs here - where the ISPC headers are generated
# src/core/ispc/CMakeLists.txt
add_library(IspcLib STATIC simd_code.ispc)
# No include dirs or link libs since the ispc code is stand-alone
# src/runner/CMakeLists.txt
add_executable(ProjectExe main.cpp)
target_link_libraries(ProjectExe PRIVATE CoreLib)
Surprisingly, I am able to build my CoreLib target (core_code.cpp includes simd_code_ispc.h
, the generated header). Looking at the make file, the include directory it specifies when building the core target is
C:\\...\MyProject\cmake-build-debug\src\core\ispc\CMakeFiles\IspcLib.dir\\.\
which sure enough is where ISPC generated the files.
I am not able to build my runner target that depends on core, with an error that the #include simd_code_ispc.h
is not found.
I know I could hard code this directory into my includes, but I'm looking for how I should do this; in a way that is not specific to my machine, that still allows me to rearrange my project structure, and will work during build and install time.
I have seen a few examples online that use a custom command (including this stack exchange post) but CMake added an ISPC integration in 3.19, so I would far prefer to use it.
Use target's property ISPC_HEADER_DIRECTORY
(CMake documentation):
# You may need to add ISPC to project's languages if you mix languages
project(TEST_ISPC LANGUAGES ... ISPC)
# Add `.ispc` as regular sources files.
add_library(ispc_lib STATIC simple.ispc)
# `.ispc` header files are generated in `ISPC_HEADER_DIRECTORY`
target_include_directories(ispc_lib PUBLIC $<TARGET_PROPERTY:ISPC_HEADER_DIRECTORY>)
# Now, linking targets can include generated `.ispc` header files.
add_executable(test_ispc some_source_file.cpp ...)
target_link_libraries(test_ispc PRIVATE ispc_lib)
Following properties are available:
ISPC_HEADER_DIRECTORY
per target, or CMAKE_ISPC_HEADER_DIRECTORY
globally (default CMAKE_CURRENT_BINARY
) (see CMake documentation.ISPC_HEADER_SUFFIX
per target, or CMAKE_ISPC_HEADER_SUFFIX
globally (default _ispc.h
) (see CMake documentation.ISPC_INSTRUCTION_SETS
per target, or CMAKE_ISPC_INSTRUCTION_SETS
globally (default should be the most capable one if we follow ispc's documentation) (see CMake documentation.If you want to change a property, use:
set_target_property(ispc_lib PROPERTIES ISPC_HEADER_DIRECTORY ...)