Nvcc — добавить флаги к определенному файлу с помощью cmake

Я пишу проект CXX+CUDA и компилирую его с помощью nvcc и CXX-компилятора icpc.

Я хочу добавить разные флаги компиляции icpc для разных файлов. В автономном режиме CXX это возможно с помощью метода set_source_files_properties(), но я попробовал его в своем случае, и он не сработал.

Минимальный пример для моей структуры -

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}>)

При компиляции этого проекта флаги --compiler-options действительно правильно передаются в icpc, но мне нужны разные флаги для каждого источника. Например, я бы хотел, чтобы file1.cu также компилировался с -pedantic -Werror.

Я пытаюсь сделать это, добавив:

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

в файл CMakeLists.txt, но я не вижу никаких изменений в команде компиляции, примененной к этому файлу (я проверял с помощью VERBOSE=1 make). После PROPERTIES я попробовал еще несколько вариантов, но ни один из них не сработал.

Как я могу применить разные дополнительные флаги компиляции к разным файлам?


Примечание. Я хочу, чтобы компиляция выполнялась автоматически с использованием CMake, поскольку у меня большой проект со множеством компонентов, поэтому использование метода CUDA_COMPILE в моем штате не актуально. Я ищу какой-то параллельный метод set_source_files_properties(), который применим в моей сфере.


Я использую icpc 2021.4, nvcc 12.2 и cmake 3.21.4.

COMPILE_FLAGS был заменен на COMPILE_OPTIONS, но я не думаю, что это причина.
paleonix 16.04.2024 13:08
target_compile_features(proj PRIVATE cxx_std_17 cuda_std_17) — это предпочтительный способ указания (минимальных) требуемых стандартов в целевой области (я не знаю, нужно ли вам это также и в области исходного файла). Также обратите внимание, что CMake теоретически может принять решение использовать более высокий стандарт, поскольку он просто определяет минимум. Кроме того, CMake обычно допускает расширения компилятора (т. е. он использует -std=gnu++17 с g++, если вы это позволяете), поэтому я обычно ставлю set(CMAKE_CXX_EXTENSIONS OFF) перед project(), чтобы избежать этого.
paleonix 16.04.2024 13:16
-lstdc++fs — флаг компоновщика. Он не должен быть частью опций компилятора. Вместо этого используйте target_link_libraries(proj PRIVATE stdc++fs).
paleonix 16.04.2024 17:17
include_directories(${CMAKE_CUDA_TOOLKIT_INCLUDE_DIRECTORIES‌​}) тоже не должно быть необходимости. Как упоминается в документации , это может быть (только) полезно при компиляции .cpp файлов, использующих некоторый API CUDA. Даже в этом случае есть более простой способ использовать find_package(CUDAToolkit) и связать предоставляемые им цели.
paleonix 16.04.2024 17:28

@paleonix Большое спасибо за все идеи! Я постараюсь, насколько смогу, применить их к своему коду (мой реальный проект, конечно, намного сложнее). К сожалению, мой код в значительной степени зависит от файлов .cu, выполняющих операции с хостом, которые необходимо скомпилировать с определенными флагами C++. Статический анализ был на самом деле просто ради примера, и фактические флаги, которые мне нужны, разные (и относятся к конкретной архитектуре процессора). Просто чтобы убедиться, что я вас правильно понял: нет решения моей проблемы? (т. е. создание разных команд nvcc для разных файлов)

Amit 16.04.2024 18:26

Вы можете попробовать сделать это на целевом уровне и установить разные цели для разных исходных файлов. Т.е. создавать статические библиотеки из file1.cu и file2.cu, которые затем связываются с целевым исполняемым файлом.

paleonix 16.04.2024 18:37

Интересная идея, попробую, посмотрим, получится ли у меня что-нибудь.

Amit 16.04.2024 19:09

@paleonix - Ваше решение, кажется, работает и на самом деле имеет смысл «компилировать» (имея отдельные цели для ЦП, графического процессора и «универсальных» файлов — каждый компилируется в разных настройках. Связь также кажется довольно гладкой. Спасибо!

Amit 17.04.2024 09:22

Происходит ли это с GCC, а не с ICPC?

einpoklum 17.04.2024 11:39
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
9
187
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Редактировать: Хотя я был уверен, что воспроизвел проблему COMPILE_FLAGS с игнорированием исходных файлов CUDA, я больше не могу ее воспроизвести. Т.е. Должно быть, я сам впервые столкнулся с какой-то проблемой и не могу понять, как это сделать (ни с GGC в качестве хост-компилятора, ни с ICPC).


Самый простой обходной путь (и, возможно, даже лучшая стратегия и стиль, независимые от этой конкретной проблемы) — это иметь цель CMake (например, статическую библиотеку) для каждого файла или группы файлов, для которых требуются разные параметры компилятора. API-интерфейсы целевого уровня для установки параметров компилятора работают без проблем и более элегантны в использовании (избегая явных имен свойств, таких как COMPILE_OPTIONS, в пользу имен функций CMake, таких как target_compile_options(), target_compile_features() и т. д., с простой спецификацией PRIVATE против PUBLIC).

Все эти цели затем можно связать с исполняемой целью, используя target_link_libraries().

Ответ принят как подходящий

Это проблема с комбинацией файлов CMakeLists + флагов.

Я только что создал проект, похожий на ваш (скорее MWE...) с CMake 3.28.3, и не столкнулся с этой проблемой.

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; }

и вот как выглядит сборка:

$ 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

Итак, одна компиляция и одна компоновка не имели проблем, а одна компиляция жаловалась на неиспользуемый параметр - как и ожидалось.

... но вы всегда можете обернуть компиляцию файлов целевыми объектами библиотеки.

Предположим, у вас есть четыре файла:

  • main.cu можно скомпилировать без специальных флагов для кода на стороне хоста
  • file1.cu необходимо скомпилировать с флагом -O1 для кода на стороне хоста
  • file2.cu и file3.cu необходимо скомпилировать с флагом -Ofast для кода на стороне хоста.

Теперь используйте «цель объектной библиотеки» для каждой комбинации флагов компиляции:

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)

Теперь вы можете использовать команду настройки параметров компиляции CMake для каждой цели, например:

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

Примечания. Второй подход — это та же основная идея, что и ответ @paleonix, но с библиотеками OBJECT.

У меня в глубине души было, что в последний раз, когда я пытался использовать объектные библиотеки в CMake с CUDA, это не сработало, поэтому я не упомянул их. Но я не проверял еще раз, поэтому, если это работает, это (немного) лучше, чем статические библиотеки, поскольку позволяет избежать помещения объектных файлов в архив.

paleonix 17.04.2024 12:19

Согласен, у меня с объектными библиотеками все работало нормально.

Amit 17.04.2024 12:48

@paleonix: На самом деле оба наших подхода не имеют значения, потому что set_source_files_properties отлично работает с ICPC и NVCC, поэтому я исправил свой ответ.

einpoklum 17.04.2024 12:58

Я действительно думаю, что целевой подход чище.

Amit 17.04.2024 13:13

@Amit: 1. Вводятся искусственные объекты. 2. Если вы можете убедиться, что set_source_files_properties() работает, я считаю, что вам следует либо изменить принятый ответ, либо хотя бы несколько отредактировать вопрос.

einpoklum 17.04.2024 14:39

Я еще раз проверю это как в своем игрушечном проекте, так и в своем реальном коде.

Amit 17.04.2024 15:11

Обновляю это благодаря @einpoklum. Я нашел проблему в своих исходных списках CMakeLists, и set_source_file_properties действительно работает в этой среде. Так что мой вопрос был по сути излишним, но я бы все равно оставил предложенное вами решение с дополнительными целями, честно говоря, я думаю, что оно чище. Спасибо за помощь!

Amit 18.04.2024 10:14

@Амит, не могли бы вы рассказать, что вызвало у вас проблему?

paleonix 18.04.2024 10:26

Другие вопросы по теме