Создайте отдельные объектные файлы из одного и того же исходного кода и создайте ссылку на исполняемый файл с 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 - ... и решение вопроса: окончательный