how to set link flag for specific target (MKL) and deal with the dependence between several libraries

I write a project which is composed of several libraries and Intel MKL library. I want to use CMake to compile my project and I have two CMakeLists.txt as the following.

In the root directory,

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)


# use the new policy to allow CMake to link target libraries from other directories
cmake_policy(SET CMP0079 NEW)
set(CMAKE_CXX_FLAGS "-o2 -msse -msse2 ${OpenMP_CXX_FLAGS}")


set(MKL_ROOT "/opt/intel/compilers_and_libraries_2019.4.243/linux/mkl")

# In the future modification, I will wirte my own find_package module.
# Now we set this path manually.
set(GSL_LIBRARY_PATH /usr/lib/x86_64-linux-gnu/libgsl.a)
set(DL_LIBRARY_PATH /usr/lib/x86_64-linux-gnu/libdl.a)

set(MKL_LIBRARY_FLAGS "-Wl,--start-group ${MKL_ROOT}/lib/intel64/libmkl_intel_lp64.a") 
set(MKL_LIBRARY_FLAGS "${MKL_LIBRARY_FLAGS} ${MKL_ROOT}/lib/intel64/libmkl_gnu_thread.a")
set(MKL_LIBRARY_FLAGS "${MKL_LIBRARY_FLAGS} ${MKL_ROOT}/lib/intel64/libmkl_core.a -Wl,--end-group -lgomp -lpthread -lm -ldl")

find_package(Boost 1.58.0 COMPONENTS program_options REQUIRED)
find_package(OpenMP REQUIRED)



add_executable(MMNET ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)

target_link_libraries(dataIO PUBLIC ${Boost_LIBRARIES})
target_link_libraries(Params PUBLIC dataIO)
target_link_libraries(GenoData PUBLIC GenotypeBasis)
target_link_libraries(AuxGenoData PUBLIC GenotypeBasis)
target_link_libraries(GeneticCorr PUBLIC NumericUtils GenoData AuxGenoData)
target_link_libraries(LMMCPU PUBLIC GenoData)

list(APPEND LINK_STATIC_LIBRARIES dataIO Params Timer GenoData MemoryUtils
                                  LMMCPU NumericUtils GeneticCorr GenotypeBasis

target_link_libraries(MMNET PUBLIC ${LINK_STATIC_LIBRARIES} 

In the subdirectory,

add_library(dataIO STATIC IOUtils.h
add_library(Timer STATIC Timer.h
add_library(Params STATIC Parameters.h
add_library(MemoryUtils STATIC MemoryUtils.h
add_library(NumericUtils STATIC NumericUtils.h
add_library(GenoData STATIC GenoData.h
add_library(GeneticCorr STATIC GeneticCorr.h
add_library(GenotypeBasis STATIC GenotypeBasis.h
add_library(AuxGenoData STATIC AuxGenoData.h

MESSAGE(STATUS "Finish building libraries")

In terms of the CMakeLists.txt file from the root directory, there are three lines to deal with the Intel MKL library. I am not sure if there is another beautiful way to solve this problem.

set(MKL_LIBRARY_FLAGS "-Wl,--start-group ${MKL_ROOT}/lib/intel64/libmkl_intel_lp64.a") 
set(MKL_LIBRARY_FLAGS "${MKL_LIBRARY_FLAGS} ${MKL_ROOT}/lib/intel64/libmkl_gnu_thread.a")
set(MKL_LIBRARY_FLAGS "${MKL_LIBRARY_FLAGS} ${MKL_ROOT}/lib/intel64/libmkl_core.a -Wl,--end-group -lgomp -lpthread -lm -ldl")

What’s more, in my root CMakeLists.txt file, I write several targe_link_libraries command to deal with the dependence between libraries. Is there any other better ways to do? Thank you!

Depending on which part of MKL you use you may simply
set(BLA_VENDOR Intel10_64lp)

note that you have one for GSL too:

other remarks:

  1. You should avoid using ${Whatever_VAR} in TLL and include_directories and use appropriate imported target in TLL i.e. target_link_libraries(dataIO PUBLIC Boost::program_options), this will bring appropriate library and include requirement in one usage requirement.
  2. You use OpenMP_CXX_FLAGS before find_package(OpenMP REQUIRED) this won’t work. And you’d better use OpenMP::OpenMP_CXX imported target and not OpenMP_CXX_FLAGS var.
  3. cmake_minimum_required(VERSION 3.5) 3.5 is ancient
  4. I think you’d better write the target_link_libraries(...) in the same CMakeLists.txt as the one defining the libs, those requirements are part of the definition of the libraries and should be (I think) near their respective add_library statement.

@erk Thank you for your patient instruction. I fully agree with your remark 3 and remark4. I still have several confusion point. First of all, I do not clearly understand your first remark. After I find the Boost package, I want to include the boost header file search path and link it to my library dataIO. With respect to your remark2, it is better for me to link the OpenMP:OpenMP_CXX directly with my library instead of using compiler flag. Is it right? What’s more, how should I do to make a lot of target_link_library command more neat? Thank you so much!

Precisely if you
target_link_libraries(dataIO PUBLIC Boost::program_options) you’ll get exactly what you need, because the include search path comes with the imported target Boost::program_options.
Basically with modern CMake your target (library or executable usually only need to target_link_libraries(...) the libraries they are using. Basically a CMake target shall convey all necessary informations to use it.

Yes that’s what I meant. For every library which uses OpenMP you do:
target_link_libraries(theLib PUBLIC OpenMP::OpenMP_CXX)
this will have the benefit to show which library does in fact need OpenMP.

In your current setup, you will have OpenMP FLAGS enabled for every target even though some of them may not need that.