1
votes

I'm brand new to the world of linux, cmake, and software/computers in general (I'm just learning how to work with the command line if that gives you an idea of where I'm at) yet somehow found myself working as a software intern (I'm an EE major). I've been tasked to build a software package using cmake and make and it is not going well. I'm making an effort to understand every single line within the top level CMakeLists.txt file associated with the package and am feeling incredibly incompetent. I've gone through some documentation about cmake in general and although I have a sense of how cmake uses CMakeLists.txt files there are some specifics that require clarification.

1) There are a number of variables that are being used and I would like to find out what their values are. However, not all of the variables within the CMakeLists.txt file are shown in the CMakeCache.txt file. For example, consider the following command shown below

SET(bioreader_common_LIBS

${bioreader_common_LIBS}

    QtCore
    QtScript
    QtScriptTools
    QtNetwork
    QtGui
    QtTest
    QtXml
    QtDBus
    QtSql

    mongoclient.a
    bsd
    ssl
    crypto
    boost_system
    boost_thread
    boost_filesystem
    boost_program_options
    )

Nowhere in the CMakeLists.txt file is the variable bioreader_common_LIBS defined and its not contained in the cache. It seems obvious that it's "value" is simply a list of libraries. Is there a way (maybe through the command line) to return the value of this variable?

2) After a google search about cmake variables I came across a wiki page detailing useful cmake variables (http://www.cmake.org/Wiki/CMake_Useful_Variables). I've been trying to find the value of a lot of these variables but with little luck. For example, one of the "useful variables" is CMAKE_LIBRARY_PATH. Although there is no reference to this variable within the CMakeLists.txt or CMakeCache.txt files, it seems as though it should still exist and have a value and yet I can't find it?

3) One of the biggest issues I've run into after running cmake and make is failing to link against certain libraries. For example, there is a required sql database driver plugin (mysql) which I believe exists as 12 .so files located in usr/lib/mysql/plugin. I realize that I need to modify the CMakeLists.txt file to include these libraries or perhaps add the path somewhere but I'm not sure how to do it. Even if I knew where to add the library I'm not sure how to name the library within the CMakeLists.txt (I thought the name of the driver was "mysql" but apparently that's technically not what you would refer to it as within the CMakeLists.txt file).

The CMakeLists.txt file I'm referring to is shown below. Sorry if this question seems stupid but I'm totally lost and feeling very frustrated.

cmake_minimum_required(VERSION 2.4)
if(COMMAND cmake_policy)
  cmake_policy(SET CMP0003 NEW)
endif(COMMAND cmake_policy)

project (bioreader)

set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/;${CMAKE_MODULE_PATH}")
# Find Qt libraries
INCLUDE(FindQt4) # will find QMake moc includes and libraries for us
INCLUDE(${QT_USE_FILE})
FIND_PACKAGE(Qt4 REQUIRED)
LINK_DIRECTORIES(${QT_LIBRARY_DIR})

# Find MongoDB libraries
FIND_PACKAGE(MongoDB REQUIRED)

# Find Boost libraries
FIND_PACKAGE(Boost REQUIRED)

# Custom dependencies
INCLUDE(AddFileDependencies)

# Qt/Qtopia
include (${QT_USE_FILE})
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR}/QtCore/)
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR}/QtGui/)
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR}/QtNetwork/)
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR}/QtScript/)
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR}/QtScriptTools/)
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR}/QtTest/)
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR}/QtXml/)
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR}/QtDBus/)
INCLUDE_DIRECTORIES(${QT_INCLUDE_DIR}/QtSql/)

# Optimized?
OPTION (OPTIMIZED "Compile in the optimized mode?" ON)
OPTION (ATOM "Optimize for Intel Atom 32-bit?" OFF)
OPTION (PROFILING "Add profiling information to executable?" OFF)
ADD_DEFINITIONS (-Wall -fno-strict-aliasing -Wno-strict-aliasing)

IF(OPTIMIZED)
  ADD_DEFINITIONS (-O3)
IF (ATOM)
  ADD_DEFINITIONS (-m32 -march=core2 -mtune=pentium -mfpmath=sse)
ENDIF (ATOM)
ELSE(OPTIMIZED)
  ADD_DEFINITIONS (-g)
ENDIF(OPTIMIZED)

IF(PROFILING)
  ADD_DEFINITIONS (-pg)
ENDIF(PROFILING)

# Ban exceptions? (used only for testing/refactoring)
OPTION (KILL_EXCEPTIONS "Disable support for exceptions?" OFF)
IF (KILL_EXCEPTIONS)
  ADD_DEFINITIONS(-fno-exceptions)
ENDIF(KILL_EXCEPTIONS)

# Attempt to compile the code with ALL warnings enabled (ie. "pedantic
# mode")?
OPTION (PEDANTIC_MODE "Compile with all compiler warnings enabled?" ON)
IF (PEDANTIC_MODE)
  ADD_DEFINITIONS (-pedantic -Wno-long-long -DUSING_PEDANTIC_MODE)
ENDIF (PEDANTIC_MODE)

# Linear algebra library
OPTION (LAPACK "Use LAPACK linear algebra library" ON)
IF(LAPACK)
  MESSAGE(STATUS "Building using LAPACK.")
  ADD_DEFINITIONS (-DUSING_LAPACK)
ELSE(LAPACK)
  MESSAGE(STATUS "Building WITHOUT using LAPACK.")
ENDIF(LAPACK)

# Package subdirectories. These statements load the CMakeLists.txt files
# from the subordinate directories.

##
add_subdirectory (src/IO)
add_subdirectory (src/Instrument)
add_subdirectory (src/Protocol)
add_subdirectory (src/Script)
add_subdirectory (src/Physical)

add_subdirectory (rc/data)
add_subdirectory (rc/jslib)
add_subdirectory (rc/gfx)
add_subdirectory (rc/svninfo)


# Set up generic includes
include_directories (${bioreader_SOURCE_DIR})
include_directories (${bioreader_SOURCE_DIR}/src)
link_directories (${bioreader_BINARY_DIR})
link_directories (/usr/lib)

##
include_directories(${Boost_INCLUDE_DIRS})
link_directories(${Boost_LIBRARY_DIRS})

SET (bioreader_common_LIBS
    Instrument

    rcjslibCore
    rcjslibBioScript
    rcjslibRobot
    rcgfx
    rcsvninfo
    rcdata

    Physical
    PhysicalController
    PhysicalUnit

    Protocol
    IO
    IOqextserialport
)

SET(bioreader_common_LIBS
${bioreader_common_LIBS}

QtCore
QtScript
QtScriptTools
QtNetwork
QtGui
QtTest
QtXml
QtDBus
QtSql

mongoclient.a
bsd
ssl
crypto
boost_system
boost_thread
boost_filesystem
boost_program_options
)

IF(LAPACK)
  SET (bioreader_common_LIBS
        ${bioreader_common_LIBS}
        lapack
        blas
        gfortran)
ENDIF(LAPACK)

SET (bioreader_reader_LIBS
    InstrumentBuilderReader
    InstrumentBuilderUnitTest

    ProtocolTest
    InstrumentTest
    PhysicalControllerTest
    PhysicalUnitTest
    InstrumentBioTest

    InstrumentBio
    Script

    PhysicalPump
    PhysicalElevator
    PhysicalMotor
    PhysicalRobot

    ${bioreader_common_LIBS}
)

##
## BIOSCALE_QUICKAPP  APPNAME  SOURCES src1.cpp src2.cpp LIBS
##
MACRO(BIOSCALE_QUICKAPP APPNAME)

SET(__MODE "SOURCES") # default

FOREACH(ARG ${ARGN})
  IF( ${ARG} STREQUAL "SOURCES" )
    SET(__MODE "SOURCES")
  ELSEIF( ${ARG} STREQUAL "LIBS" )
    SET(__MODE "LIBS")
  ELSE( ${ARG} STREQUAL "SOURCES" )
    ##
    ## source
    ##
  IF( ${__MODE} STREQUAL "SOURCES")
     SET(${APPNAME}_SRCS ${${APPNAME}_SRCS} ${ARG}) # append to var
  ENDIF( ${__MODE} STREQUAL "SOURCES")

  ##
  ## libs
  ##
  IF( ${__MODE} STREQUAL "LIBS")
     SET(${APPNAME}_LIBS ${${APPNAME}_LIBS} ${ARG}) # append to var
  ENDIF( ${__MODE} STREQUAL "LIBS")
  ENDIF( ${ARG} STREQUAL "SOURCES" )
ENDFOREACH(ARG)

QT4_AUTOMOC(${${APPNAME}_SRCS})

add_executable(${APPNAME} ${${APPNAME}_SRCS})
target_link_libraries(${APPNAME} ${${APPNAME}_LIBS})

ENDMACRO(BIOSCALE_QUICKAPP)

## Configuration for all targets
SET (bioreader_SRCS src/universal.cpp)

# Executable target for unit tests
BIOSCALE_QUICKAPP (unittest 
    SOURCES ${bioreader_SRCS}
    LIBS    ${bioreader_reader_LIBS})

# Executable target for reader
BIOSCALE_QUICKAPP (reader 
    SOURCES ${bioreader_SRCS}
    LIBS    ${bioreader_reader_LIBS})

IF(PROFILING)
  SET_TARGET_PROPERTIES(reader PROPERTIES LINK_FLAGS -pg)
ENDIF(PROFILING)
1
You can print out the values of variables using message(status, "The variable's value is " ${variable_name}). There are some files like FindBoost.cmake, they are coming with CMake already, if you cannot find the one appropriate for you you can search the internet, already some people might have created one, with a little update they generally work.. cmake.org/cmake/help/git-master/manual/cmake-modules.7.html - phoad

1 Answers

0
votes

This is a big post and I may not get to answering all of it in one shot. But, I will start at the top and try to answer what I come across. It seems like any understanding will get you farther than you are. Who knows, maybe I'll even answer the real question.

Q1) "Nowhere in the CMakeLists.txt file is the variable bioreader_common_LIBS defined "

A1) SET(bioreader_common_LIBS ${bioreader_common_LIBS} QtCore QtScript .... ) is defining bioreader_common_LIBS. What the set call is doing is saying, "Set bioreader_common_LIBS to whatever it's currently defined as ( note the syntx ${ .. } which gives you the value of the variable. ) plus what ever follow, e.g. the Qt libs. You can see how that same type of line is used lowe in your file, that is appending to the current value of bioreader_common_LIBS

Q2) bioreader_common_LIBS defined and its not contained in the cache. A2) To add it to the cache, the set call would look like .. set(bioreader_common_LIBS ${bioreader_common_LIBS} lib1 lib2 CACHE STRING "")

Q3 A3) The 'Useful CMake variables' are set by CMake when appropriate and and won't exist in your CMakeLists.txt necessarily, unless you are setting them to something you need. Id you want to see the value of any variable, try, e.g. message( "var_name: ${var_name}" ) to see the value of var_name. Those messages will print when you configure the project.

Q4) The rest ... A4) One thing to remember is, every subdirectory has a CMakeLists.txt file in that controls configuring/building the libraries therein.

To find your libraries, follow the example of Boost in your CMakeLists. Use a find_package(MySQL REQUIRED) call with your correct package name. You can find the CMake supplied Modules in the CMake_install_directory/Modules. If there isn't one, then you'll need to write it. Find modules provide several useful variable when then succeed. They are described in the file usually, but roughly you'll get ( using MySQL as the example ) MySQL_FOUND - tells if CMake found it, MySQL_INCLUDE_DIR - the path the headers, MySQL_LIBRARIES and/or MySQL_LIBRARY - the names of the library(s), MySQL_LIB_DIR - the library directory.

Now, you see in your CMake file, include_directories, you can add include_directories(${MySQL_INCLUDE_DIR}) to your project to add it to your -I of the compiler args. You can use link_directories(${MySQL_LIB_DIR}) to add that directory for linking. Now, to link your library, call target_link_libraries(my_lib ${MySQL_LIBRARIES})

One thing to notice, your current CMake file has some bad habits going on, namely, it explicitly names the libraries to linke. That is not recommended as it binds you pretty tightly to the whims of the library providers. The names can change, so you're better foo always using the variables you're given from the find modules. Also, I don't believe you ever need to add link_directories (/usr/lib) since that directory is usually already in the default search path, though I guess it won't hurt to have it.

That should get you moving in the right direction, I've typed for too much for one sitting.