Search code examples
cmakecudanvcccompiler-flags

nvcc - add flags to a specific file using cmake


I am writing a CXX+CUDA project, and I'm compiling using nvcc, with CXX compiler of icpc.

I want to add different compilation flags for icpc for different files. In CXX standalone this is possible using set_source_files_properties() method, but I tried it in my case and it didn't work.

Minimal example for my structure -

cat main.cu
#include "file1.cuh"
#include "file2.cuh"

int main() {

    int3 size = make_int3(1, 1, 1);
    std::cout << size.x << std::endl;
    print_x<<<1,1>>>(size);
    print_y<<<1,1>>>(size);
    return 0;
}
cat file1.cuh
#include <cuda_runtime.h>

__global__ void print_x(int3 arr);
cat file1.cu
#include "file1.cuh"
#include <iostream>

__global__ void print_x(int3 arr) { printf("%d", arr.x); }
cat file2.cuh
#include <cuda_runtime.h>
#include <iostream>

__global__ void print_y(int3 arr);
cat file2.cu
#include "file2.cuh"

__global__ void print_y(int3 arr) { printf("%d", arr.y); }
cat CMakeLists.txt
set(CMAKE_C_COMPILER "icc")
set(CMAKE_CXX_COMPILER "icpc")
set(CMAKE_CUDA_COMPILER "nvcc")
project(proj LANGUAGES CXX CUDA)

set(COMMON_CC_COMPILER_FLAGS -std=c++17 -Wextra -pedantic -Werror -Wall -lstdc++fs)
set(COMMON_FLAGS ${COMMON_CC_COMPILER_FLAGS})
string(JOIN ", " COMMON_FLAGS_FOR_CUDA_CC_COMPILER "${COMMON_CC_COMPILER_FLAGS}")
string(REPLACE ";" "," COMMON_FLAGS_FOR_CUDA_CC_COMPILER "${COMMON_FLAGS_FOR_CUDA_CC_COMPILER}")
set(CMAKE_CUDA_STANDARD 17)
set(COMMON_FLAGS_CUDA -ccbin=icpc --compiler-options "${COMMON_FLAGS_FOR_CUDA_CC_COMPILER}")
string(REPLACE ";" " " FLAGS "${COMMON_FLAGS}")
list(APPEND COMMON_FLAGS -DFLAGS="${FLAGS}")

include_directories(${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES})

add_executable(proj main.cu file1.cu file2.cu)
target_compile_options(proj PRIVATE $<$<COMPILE_LANGUAGE:CXX>:${COMMON_FLAGS}> $<$<COMPILE_LANGUAGE:CUDA>:${COMMON_FLAGS_CUDA}>)

When compiling this project, the flags under --compiler-options indeed pass correctly to icpc, but I want different flags for each source. For example, I would like file1.cu to also be compiled with -pedantic -Werror.

I'm trying to do this by adding:

set_source_files_properties(
    file1.cu
    PROPERTIES 
    COMPILE_FLAGS "--compiler-options -Wall")

to the CMakeLists.txt file, but I see no change in the compilation command applied for this file (I checked using VERBOSE=1 make). I tried several other variations after PROPERTIES, but none of them work.

How can I get different additional compilation flags to apply to different files?


Note: that I want the compilation to be done automatically using CMake since I have a large project with many components, so usage of CUDA_COMPILE method is not relevant in my state. I'm looking for some parallel method to set_source_files_properties() which is applicable in my scope.


I am using icpc 2021.4, nvcc 12.2, and cmake 3.21.4.


Solution

  • It's problem with your CMakeLists files + flags combination

    I just built a project similar to yours (more of an MWE...) with CMake 3.28.3, and did not experience this problem.

    CMakeLists.txt:

    cmake_minimum_required(VERSION 3.25 FATAL_ERROR)
    set(CMAKE_CUDA_COMPILER "nvcc")
    set(CMAKE_CUDA_HOST_COMPILER "icpc")
    project(my_proj LANGUAGES CXX CUDA)
    
    add_library(my_proj foo.cu bar.cu)
    set_source_files_properties(foo.cu
        PROPERTIES COMPILE_FLAGS "--compiler-options -Wunused-parameter")
    

    foo.cu:

    int foo(int x) { return (100 > 1) == 3; }
    

    bar.cu:

    int bar(int x) { return (100 > 1) == 3; }
    

    and this is what the build looks like:

    $ cmake --build build
    [2/3] Building CUDA object CMakeFiles/my_proj.dir/foo.cu.o
    /tmp/delme/foo.cu: In function ‘int foo(int)’:
    /tmp/delme/foo.cu:1:13: warning: unused parameter ‘x’ [-Wunused-parameter]
     int foo(int x) { return (100 > 1) == 3; }
             ~~~~^
    [3/3] Linking CUDA static library libmy_proj.a
    

    so, one compilation and one linking had no issues, and one compilation complained about the unused parameter - just as expected.

    ... but you can always wrap file compilations with object library targets.

    Let's suppose that you have four files:

    • main.cu can be compiled with no special flags for the host-side code
    • file1.cu needs to be compiled with flag -O1 for the host-side code
    • file2.cu and file3.cu need to be compiled with flag -Ofast for the host-side code.

    Now, use an "object library target" for each combination of compilation flags:

    add_library(compiled_with_o1 OBJECT file1.cu)
    add_library(compiled_with_ofast OBJECT file2.cu file3.cu)
    add_executable(my_program main.cu) # no special wrapping for main.cu
    target_link_libraries(my_program compiled_with_o1 compiled_with_ofast)
    

    You can now use CMake's per-target compilation options setting command, like so:

    target_compile_options(compiled_with_o1 PRIVATE "--compiler-options -O1")
    target_compile_options(compiled_with_ofast PRIVATE "--compiler-options -Ofast")
    

    Notes: The second approach is the same basic idea as @paleonix' answer, but with OBJECT libraries.