1

I have two files main.cpp and simd.cpp. I compile them like this:

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

Now I want to build this with Cmake. Here is my CMakeLists.txt file:

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

With MSVC2012 this works fine. However, it makes two separate folders in the build file, sse and avx, which each point to the same simd.cpp. I guess this is a fine solution since I can set the properties separately for each folder. It's a bit annoying having the same source file displayed twice.

But when I make a makefile for GCC in Linux I get the error:

<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

Can you explain why the Makefile is failing? Can you suggest a better CMakeLists.txt file to do what I want to do?

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();
}
Z boson
  • 32,619
  • 11
  • 123
  • 226
  • `:0:1: error: macro names must be identifiers` something bad happens in command line argument? –  May 22 '14 at 14:28
  • 1
    Why are you using `COMPILE_DEFINITIONS` for linux and `COMPILE_FLAGS` for msvc? –  May 22 '14 at 14:29
  • Hey! Thanks! You solved it. How embarrassing :-/ The COMPILE_FLAGS was defined but not COMPILE_DEFINTIONS. I changed COMPILE_DEFINTIONS to COMPILE_FLAGS and it works. I started using cmake yesterday. Wish I had some warning for this! I originally intended this post to just be about visual studio and I only tested GCC on linux during the post. In any case, is this a good soltuion? If you have a better solution could you post it? – Z boson May 22 '14 at 14:37
  • IS there some way to have Cmake warn me about undefined variables to help avoid these kind of errors in the future? I just tried using random name and it makes the Makefile with no warning. – Z boson May 22 '14 at 14:45
  • `is this a good soltuion` I think it's quite appropriate for this kind of task. I have some code review thoughts if you want I can make it as an answer) –  May 22 '14 at 14:46
  • `about undefined variables` You add a compile definition, so it's compiler job to report you unused definition warning –  May 22 '14 at 14:48
  • @ruslo, I mean a CMAKE variable defined with set(). I never defined COMPILE_DEFINTIONS but Cmake never warned me. I can put any random name there and it gives no warning. – Z boson May 22 '14 at 14:50

1 Answers1

2

The reason is a misprint:

set_target_properties(avx PROPERTIES COMPILE_DEFINITIONS "-mavx")

Compiler output:

> 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

So definitions -mavx passed to compiler.

Notes

  • Compiler flags combined from both CMAKE_CXX_FLAGS and CMAKE_CXX_FLAGS_RELEASE (for Release build) simultaniously. So there is no need to modify CMAKE_CXX_FLAGS_RELEASE if CMAKE_CXX_FLAGS already modified: edit #1
  • -O3 option already passed to CMAKE_CXX_FLAGS_RELEASE no need to modify it (btw you rewrite -DNDEBUG release option, I think it's pretty important): edit #2
  • Use COMPILE_DEFINITIONS to modify -D... flags (btw you define __SSE2__ only for msvc, is it correct?): edit #3
  • Refactor lit' bit: edit #4
  • Now you see one of the popular CMake anti-pattern: set(CMAKE_CXX_FLAGS "my flags"). By default (and sometimes by user needs) CMAKE_CXX_FLAGS is not empty variable, so right way to modify it is: set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} my flags"): edit #5
  • ... and the question fix: final
  • 1
    This is a great answer! Thank You! I leaned a lot from it which will save me a lot of time as I'm learning Cmake. – Z boson May 23 '14 at 06:56