c++cmakeispc

How do I include ISPC compiler generated headers in a CMake project?


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.


Solution

  • 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:

    If you want to change a property, use:

    set_target_property(ispc_lib PROPERTIES ISPC_HEADER_DIRECTORY ...)