views:

193

answers:

2

I'm configuring my project for CMake and am having linking problems - the project files all compile successfully, then it says it is linking and reports all sorts of symbols not found.

These symbols are mostly provided by my own code, while some of them are provided by BerkeleyDB, which is being properly located and included.

Here is my top-level CMakeLists.txt:

cmake_minimum_required(VERSION 2.6)

project( rpdb C )

#   add local modules path for project
set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/Modules/" )

#   where to look for source files (headers and source)
include_directories( include src )

#   define sub-directories of source that cmake knows about as well a where their output will be put
add_subdirectory( src bin )

#   compiler-dependent flags:
if( CMAKE_COMPILER_IS_GNUCC )
    #   gcc
    add_definitions( -ggdb -fsigned-char -freg-struct-return -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Winline -Werror )
else( CMAKE_COMPILER_IS_GNUCC )
    #   non-gcc (intended for clang)
    add_definitions( -ggdb -fsigned-char -Wall -W -Wshadow -Wstrict-prototypes -Wpointer-arith -Wcast-qual -Winline -Werror )
endif( CMAKE_COMPILER_IS_GNUCC )


#   distribution configuration
set(CMAKE_C_FLAGS_DISTRIBUTION "-O3")
set(CMAKE_CXX_FLAGS_DISTRIBUTION "-O3")

And here is my src-level CMakeLists.txt:

#   make sure we have libdb
find_package( BerkeleyDB REQUIRED )
include_directories( ${libdb_INCLUDE_DIRS} )
target_link_libraries( rpdb ${libdb_LIBRARIES} )

#   define variable specifying included source files - all .c files below this directory
file( GLOB rpdb_src "**/*.c" )

#   define shared library with sources
add_library( rpdb SHARED ${rpdb_src} )

The output (partial):

...
[100%] Building C object bin/CMakeFiles/rpdb.dir/RPDB_TransactionController/RPDB_TransactionController.c.o
Linking C shared library librpdb.dylib
Undefined symbols:
  "_RPDB_ReplicationVerbositySettingsController_displayMessageProcessingInformation", referenced from:
      _RPDB_SettingsController_internal_setVerbosity in RPDB_SettingsController.c.o
...

All of the symbols do actually exist. The result seems to occur for symbols in object files other than the one it is currently looking at.

The output from "cmake ../" (from install, a directory in the top-level):

=> cmake ..
-- Found BerkeleyDB: /usr/local/lib/libdb.dylib
-- Configuring done
-- Generating done
-- Build files have been written to: /Users/ahaig/Projects/RPDB/RPDB_C/install

Any help much appreciated.

A: 

make VERBOSE=1

Also, look at CMakeCache.txt

Bill Hoffman
Asher
Problem is with inclusion of all .c files via glob - only first level down is getting included. See comment on original post.
Asher
A: 

My problem came down to an issue with file inclusion. I was including files via glob using **/*.c, which was apparently being treated as */*.c. Perhaps I'm misunderstanding glob patterns here - I have only used them minimally otherwise in Ruby's file globbing.

In any case, here is the solution I came up with:

#   function processes each sub-directory and then adds each source file in directory
#   each function should cascade back upward in setting variables so that the bottom directory
#   adds its source first, and then the level above it adds its source and passes both up, and so on...
function( recursively_include_source which_directory )

    #   get list of source from this directory
    file( GLOB this_directory_src "${which_directory}/*.c" )

    #   get list of all files for this directory
    file( GLOB this_directory_all_files "${which_directory}/*" )

    if( this_directory_all_files AND this_directory_src )

        #   remove source from list of files to get list of directories
        list( REMOVE_ITEM this_directory_all_files ${this_directory_src} )
        set( this_directory_directories ${this_directory_all_files} )

        #   for each sub-directory, call self with sub-directory as arg
        foreach( this_sub_directory ${this_directory_directories} )
            recursively_include_source( ${this_sub_directory} )
        endforeach( this_sub_directory ${this_directory_directories} )

    endif( this_directory_all_files AND this_directory_src )

    #   add source files to ${rpdb_src} in PARENT_SCOPE
    set( rpdb_src ${rpdb_src} ${this_directory_src} PARENT_SCOPE )

endfunction( recursively_include_source which_directory )

This includes all .c files in and below the current directory.

I call the function like this:

recursively_include_source( ${CMAKE_CURRENT_SOURCE_DIR} )

So the final src-dir CMakeLists.txt looks like this:

#   make sure we have libdb
find_package( BerkeleyDB REQUIRED )
include_directories( ${DB_INCLUDE_DIRS} )
set(LIBS ${LIBS} ${DB_LIBRARIES})

recursively_include_source( ${CMAKE_CURRENT_SOURCE_DIR} )

#   define shared library with sources
add_library( rpdb SHARED ${rpdb_src} )
target_link_libraries( rpdb ${LIBS} )

And everything seems to be working.

Asher
target_link_libraries should be: target_link_libraries( rpdb db )
Asher