Создайте отдельные объектные файлы из одного и того же исходного кода и создайте ссылку на исполняемый файл с CMake

У меня есть два файла main.cpp и simd.cpp. Я собираю их так:

g++ -c -mavx  -O3 simd.cpp -o simd_avx.o
g++ -c -msse2 -O3 simd.cpp -o simd_sse2.o
g++ -O3 main.cpp simd_avx.o simd_sse2.o

Теперь я хочу построить это с помощью Cmake. Вот мой файл CMakeLists.txt:

add_library(avx OBJECT simd.cpp)    
add_library(sse2 OBJECT simd.cpp)

IF(MSVC)    
    set(COMPILE_FLAGS "/openmp /Wall")    
    set_target_properties (avx PROPERTIES COMPILE_FLAGS "/arch:AVX")   
    set_target_properties (sse2 PROPERTIES COMPILE_FLAGS "/arch:SSE2 -D__SSE2__")    
    set(CMAKE_CXX_FLAGS ${COMPILE_FLAGS})    
    set(CMAKE_CXX_FLAGS_RELEASE "${COMPILE_FLAGS}")   
ELSE()    
    set(COMPILE_FLAGS "-fopenmp -Wall")    
    set_target_properties (avx PROPERTIES COMPILE_DEFINITIONS "-mavx")   
    set_target_properties (sse2 PROPERTIES COMPILE_DEFINITIONS "-msse2")    
    set(CMAKE_CXX_FLAGS ${COMPILE_FLAGS})    
    set(CMAKE_CXX_FLAGS_RELEASE "${COMPILE_FLAGS} -O3")   
ENDIF()
add_executable(dispatch main.cpp $<TARGET_OBJECTS:avx> $<TARGET_OBJECTS:sse2>)

С MSVC2012 это работает нормально. Тем не менее, он создает две отдельные папки в файле сборки, sse и avx, каждая из которых указывает на один и тот же simd.cpp. Я думаю, что это хорошее решение, так как я могу установить свойства отдельно для каждой папки. Немного раздражает, когда один и тот же исходный файл отображается дважды.

Но когда я делаю make-файл для GCC в Linux, я получаю сообщение об ошибке:

<command-line>:0:1: error: macro names must be identifiers
make[2]: *** [src/CMakeFiles/avx.dir/simd.cpp.o] Error 1
make[1]: *** [src/CMakeFiles/avx.dir/all] Error 2
make: *** [all] Error 2

Можете ли вы объяснить, почему Makefile не работает? Можете ли вы предложить лучший файл CMakeLists.txt, чтобы делать то, что я хочу?

simd.cpp

#include <stdio.h>
#ifdef __AVX__ 
void func_avx() {
    printf("avx\n");
}
#elif defined ( __SSE2__ )
void func_sse2() {
    printf("sse2\n");
}
#else
// scalar code
#endif

main.cpp

extern void func_sse2();
extern void func_avx();
       void func_dispatch();
void (*fp)() = &func_dispatch;

void func_dispatch() {
    #ifdef __AVX__
    fp = func_avx;
    #else
    fp = func_sse2;
    #endif
    fp();
}
void func() {
    fp();
}

int main() {
    func();
}

1 ответ

Решение

Причина - опечатка:

set_target_properties(avx PROPERTIES COMPILE_DEFINITIONS "-mavx")

Выход компилятора:

> cmake -H. -B_builds -DCMAKE_VERBOSE_MAKEFILE=ON
c++ -D-mavx ... 
In file included from <built-in>:
<command line>:1:9: error: macro names must be identifiers
#define -mavx 1

Итак, определения -mavx передано компилятору.

Заметки

  • Флаги компилятора в сочетании с обоими CMAKE_CXX_FLAGS а также CMAKE_CXX_FLAGS_RELEASE (для сборки выпуска) одновременно. Таким образом, нет необходимости изменять CMAKE_CXX_FLAGS_RELEASE если CMAKE_CXX_FLAGS уже изменено: редактировать #1
  • -O3 вариант уже передан CMAKE_CXX_FLAGS_RELEASE нет необходимости изменять его (кстати, вы переписать -DNDEBUG вариант релиза, я думаю, это очень важно): edit # 2
  • использование COMPILE_DEFINITIONS модифицировать -D... флаги (кстати, вы определяете __SSE2__ только для msvc, это правильно?): edit # 3
  • Реактор засветился немного: правка № 4
  • Теперь вы видите один из популярных анти-паттернов CMake: set(CMAKE_CXX_FLAGS "my flags"), По умолчанию (а иногда и по потребностям пользователя) CMAKE_CXX_FLAGS не пустая переменная, поэтому правильный способ изменить это: set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} my flags"): изменить № 5
  • ... и решение вопроса: окончательный
Другие вопросы по тегам