Niko Z.
Niko Z.

Reputation: 352

Trying to use CMake when cross compiling c/c++/cuda program

I am trying out to use CMake to cross-compile a program, but it failed with this message:

/bin/sh: 1: Syntax error: ";;" unexpected

The program compiles perfectly with a raw Makefile

Here is my CMake file:

cmake_minimum_required(VERSION 3.9)


project(my_target LANGUAGES CUDA CXX C)


include(CheckLanguage)
check_language(CUDA)


# STD
if (NOT DEFINED CMAKE_CUDA_STANDARD)
    set(CMAKE_CUDA_STANDARD 11)
    set(CMAKE_CUDA_STANDARD_REQUIRED ON)
endif()


find_package(Poco REQUIRED Foundation Util)


# Flags
set (
    CMAKE_C_STANDARD 11
)

set(
    CMAKE_CXX_STANDARD 11
)

set(
    CMAKE_C_FLAGS
    ${CMAKE_C_FLAGS}
    -c -Wall -fopenmp
)

set(
    CMAKE_CXX_FLAGS
    ${CMAKE_CXX_FLAGS}
    -c -Wall -fopenmp
)

set(
    CMAKE_CUDA_FLAGS
    ${CMAKE_NVCC_FLAGS}
    --ccbin $(CMAKE_CXX_COMPILER) -O2 -gencode -std=c++11 -dc -Werror deprecated-declarations
)



# Compile Objects

file(GLOB_RECURSE src_c   src/*.c  )
file(GLOB_RECURSE src_cpp src/*.cpp)
file(GLOB_RECURSE src_cu  src/*.cu )
file(GLOB_RECURSE src_h   src/*.h )


add_library(cobjs   STATIC ${src_c} ${src_h}  )
add_library(cppobjs STATIC ${src_cpp} ${src_h})
add_library(cuobjs  STATIC ${src_cu} ${src_h} )
target_compile_options(cobjs   PUBLIC ${CMAKE_C_FLAGS}  )
target_compile_options(cppobjs PUBLIC ${CMAKE_CXX_FLAGS})
target_compile_options(cuobjs  PUBLIC ${CMAKE_NVCC_FLAGS})


set_target_properties( cuobjs
                       PROPERTIES CUDA_SEPARABLE_COMPILATION ON)


add_executable(my_target
    ${cobjs} ${cppobjs} ${cuobjs}
    ${src_h}
)


# Include Dirs
target_include_directories(cobjs PUBLIC
    include src
)
target_include_directories(cppobjs PUBLIC
    include src
)
target_include_directories(cuobjs PUBLIC
    include src
)
target_include_directories(my_target PUBLIC
    include src
)


link_directories(
    ${POCO_HOME}
    ${METIS_HOME}
)


target_link_libraries(my_target PUBLIC
    cobjs
    cppobjs
    cuobjs
    -lPocoFoundation
    -lPocoUtil
    -lpthread
    -lgomp
    -lmetis
)


And the working Makefile:

#===============================================================================
CUDA_PATH  := /usr/local/cuda
METIS_PATH := ${METIS_HOME}
POCO_PATH  := ${POCO_HOME}

# D-debug   R-release
COMPILEMD := R

EXE := coupled.exe
CC  := gcc
CXX := g++
#===============================================================================
DIR_BIN := bin
DIR_SRC := src

CCFLAGS := -Iinclude -I$(DIR_SRC) -std=c11 -c -Wall -fopenmp
CXXFLAGS := -I$(CUDA_PATH)/include -I$(METIS_PATH)/include -I$(POCO_PATH)/include -Iinclude -I$(DIR_SRC) -std=c++11 -c -Wall -fopenmp
NVCCFLAGS := -I$(POCO_PATH)/include -I$(DIR_SRC) -std=c++11 -dc -Werror deprecated-declarations
LDFLAGS := -L$(METIS_PATH)/lib -lmetis -L$(POCO_PATH)/lib -lPocoUtil -lPocoFoundation -Llib -ltecio -lpthread -lgomp

BASENM  := $(basename $(EXE))
SUFFIX  := $(suffix $(EXE))
SRC_C   := $(shell find $(DIR_SRC) -name *.c)
SRC_CPP := $(shell find $(DIR_SRC) -name *.cpp)
SRC_CU  := $(shell find $(DIR_SRC) -name *.cu)
OBJ_C   := $(SRC_C:%.c=%.o)
OBJ_CPP := $(SRC_CPP:%.cpp=%.o)
OBJ_CU  := $(SRC_CU:%.cu=%.o)

ifeq ($(COMPILEMD), D)
    CCFLAGS += -D_DEBUG -g
    CXXFLAGS += -D_DEBUG -g
    NVCCFLAGS += -D_DEBUG -g -G
else ifeq ($(COMPILEMD), R)
    CCFLAGS += -DNDEBUG -O2
    CXXFLAGS += -DNDEBUG -O2
    NVCCFLAGS += -DNDEBUG -O2
else
    $(error error COMPILEMD($(COMPILEMD)))
endif

CCFLAGS += -DKS_FP_DOUBLE -march=native
CXXFLAGS += -DKS_FP_DOUBLE -march=native
NVCCFLAGS += -DKS_FP_DOUBLE
BASENM := $(BASENM)DP$(COMPILEMD)

ifeq ($(SRC_CU), )
    LD := $(CXX)
else
    NVCC := $(CUDA_PATH)/bin/nvcc -ccbin $(CXX)
    DEVICE_SM := 50 52 60 61 #70 75
    $(foreach SM,$(DEVICE_SM),$(eval NVCCFLAGS += -gencode arch=compute_$(SM),code=sm_$(SM)))
    $(foreach SM,$(DEVICE_SM),$(eval LDFLAGS += -gencode arch=compute_$(SM),code=sm_$(SM)))
    LD := $(NVCC)
endif

OBJ := $(OBJ_C) $(OBJ_CPP) $(OBJ_CU)
EXE := $(DIR_BIN)/$(BASENM)$(SUFFIX)
#===============================================================================
all: $(EXE)
.PHONY: all clean cleanall

$(EXE): $(OBJ)
    @mkdir -p $(DIR_BIN)
    $(LD) $^ $(LDFLAGS) -o $@

$(OBJ_C): %.o: %.c
    $(CC) $< $(CCFLAGS) -o $@

$(OBJ_CPP): %.o: %.cpp
    $(CXX) $< $(CXXFLAGS) -o $@

$(OBJ_CU): %.o: %.cu
    $(NVCC) $< $(NVCCFLAGS) -o $@

clean:
    -rm -rf $(OBJ) $(EXE)

cleanall:
    -rm -rf $(OBJ) $(DIR_BIN)/*log $(DIR_BIN)/*.exe $(DIR_BIN)/*.dat

I am sorry that I could not provide the project's source code.

I am very new to CMake, and any help will be appreciated!

EDIT

I tried the solutions given by @squareskittles which seems to solve the /bin/sh: 1: Syntax error: ";;" unexpected problem. But I got a new error which says:

c++: fatal error: no input files

Yet in the corresponding build.make file the error line writes:

/usr/bin/c++  $(CXX_DEFINES) $(CXX_INCLUDES) $(CXX_FLAGS) -o <path-to-my-cpp>/my.cpp.o -c <path-to-my-cpp>/my.cpp

EDIT2

Thanks to @squareskittles's answer, I finally get to understand how CMake works. There are actually more than one incorrect parts in the CMakeLists.txt file:

  1. CMake adds automatically -c flags to C and C++ compilers so there is no need to add it manually.

  2. It is preferred to use add_compile_options() to add compilation flags than set(CMAKE_<LANG>_FLAGS ...).

  3. link_directories should always go before add_library() and add_executable(). A modern approach instead is to use find_library(), see here.

  4. I finally gave up to manually write multiple stage compilation as I did in my Makefile, and instead added all source files in add_executable(). CMake seems to have handled the different cases perfectly.

My final working version:

cmake_minimum_required(VERSION 3.9)


project(my_target LANGUAGES CUDA CXX C)


# STD
if (NOT DEFINED CMAKE_CUDA_STANDARD)
    set(CMAKE_CUDA_STANDARD 11)
    set(CMAKE_CUDA_STANDARD_REQUIRED ON)
endif()


find_package(Poco REQUIRED Foundation Util)


# Flags
set (
    CMAKE_C_STANDARD 11
)

set(
    CMAKE_CXX_STANDARD 11
)


# Compile Objects
file(GLOB_RECURSE src_c   src/*.c  )
file(GLOB_RECURSE src_cpp src/*.cpp)
file(GLOB_RECURSE src_cu  src/*.cu )
file(GLOB_RECURSE src_h   src/*.h  )

# message(STATUS "src_c   = ${src_c}"  )
# message(STATUS "src_cpp = ${src_cpp}")
# message(STATUS "src_cu  = ${src_cu}" )
# message(STATUS "src_h   = ${src_h}"  )


add_definitions(-DKS_FP_DOUBLE)


link_directories(
    ${POCO_HOME}
    ${METIS_HOME}
)


add_executable(my_target
    ${src_c}
    ${src_cpp}
    ${src_cu}
    ${src_h}
)


# Include Dirs
target_include_directories(my_target PUBLIC
    include src
)


set_target_properties(my_target
    PROPERTIES CUDA_SEPARABLE_COMPILATION ON
)


target_link_libraries(my_target PUBLIC
    # cobjs
    # cppobjs
    # cuobjs
    -lPocoFoundation
    -lPocoUtil
    -lpthread
    -lgomp
    -lmetis
)

Upvotes: 2

Views: 1403

Answers (1)

Kevin
Kevin

Reputation: 18243

When you set the CMake compiler flag variables (or any other CMake variable), you don't need to insert semicolons ; to separate the arguments/flags. CMake will recognize newlines and spaces in the set() command and handle this for you. From the docs:

Multiple arguments will be joined as a semicolon-separated list to form the actual variable value to be set.

Try this:

set(
    CMAKE_C_FLAGS
    ${CMAKE_C_FLAGS}
    -c -Wall -fopenmp
)

set(
    CMAKE_CXX_FLAGS
    ${CMAKE_CXX_FLAGS}
    -c -Wall -fopenmp
)

set(
    CMAKE_CUDA_FLAGS
    ${CMAKE_NVCC_FLAGS}
    --ccbin $(CMAKE_CXX_COMPILER) -O2 -gencode -std=c++11 -dc -Werror deprecated-declarations
)

There is one more issue with the CMake file you posted. The add_executable() command only takes source files as arguments. You cannot use previously-defined targets as arguments. Try modifying your call to add_executable(); you already compile the C, C++, and Cuda sources into static libraries with your calls to add_library(), so maybe there is simply a main.cpp (defining your call to main()) you can include in this call:

add_executable(my_target
    main.cpp
    ${src_h}
)

Upvotes: 2

Related Questions