Karnivaurus
Karnivaurus

Reputation: 24171

CMake cannot find my library file

I want to use CMake to create a simple static library Maths, and then link to that library to create a simple executable Alpha.

Here's my directory structure:

/Maths
    /build
        /
    /CMakeLists.txt
    /maths.cpp
    /maths.h
/Alpha
    /build
        /
    /CMakeLists.txt
    /main.cpp

And here are the contents of those files:

* CMakeLists.txt (for Maths) *

cmake_minimum_required(VERSION 2.6)
project(Maths)
add_library(maths STATIC maths.cpp)

* maths.cpp *

int Double(int x)
{
    int y = x * 2;
    return y;
}

* maths.h *

int Double(int x);

* CMakeLists.txt (for Alpha) *

cmake_minimum_required(VERSION 2.8)
project(Alpha)
add_executable(alpha main.cpp ../Maths/maths.h)
target_link_libraries(maths ../Maths/build/libmaths.a)

* main.cpp *

#include <iostream>

#include "maths.h"

using namespace std;

int main()
{
    int x = 5;
    int y = Triple(x);
    cout << "The answer = " << y << endl;
    return 0;
}

So, I enter the directory /Maths/build, and run cmake ... Then, I run make. This creates the library file libmaths.a in the directory /Maths/build.

Then, I enter the directory /Alpha/build, and run cmake ... Then, I run make. However, this gives me the error message:

/usr/bin/ld: cannot find -lmaths

Why can make not find the library file that I just created?

I also tried copyiing libmaths.a and maths.h into the directory /Alpha, and changing Alpha's CMakeLists.txt to:

cmake_minimum_required(VERSION 2.8)
project(Alpha)
add_executable(alpha main.cpp maths.h)
target_link_libraries(maths libmaths.a)

But this gave the same error.

Upvotes: 6

Views: 21037

Answers (2)

Johannes S.
Johannes S.

Reputation: 4626

Use a CMakeLists.txt in the root directory

/CMakeLists.txt:

CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
PROJECT( MyProject )
ADD_SUBDIRECTORY( Maths )
ADD_SUBDIRECTORY( Alpha )

in Alpha/CMakeLists.txt:

TARGET_LINK_LIBRARIES( alpha maths ) 

Run CMake on the top-level CMakeLists.txt instead of the individual subdirectory ones

Upvotes: 3

ComicSansMS
ComicSansMS

Reputation: 54777

The essential problem here is that libmaths.a is not placed in one of the default linker directories. The bigger problem is that you passed libmaths.a to target_link_libraries in the first place.

This is bad for several reasons, but the most obvious is that it's completely non-portable. A different compiler toolchain might use a different ending than .a for static libraries, so you won't be able to build there. Also, should you ever decide to switch to dynamic linking in the future, it means refactoring your existing CMake scripts.

The proper solution is to not pass hardcoded filenames to target_link_libraries. There are two roads that you can take to avoid this.

  1. Use a find script. Essentially, you call find_library(MY_MATHLIB maths [...]) and then do target_link_libraries(alpha ${MY_MATHLIB}) instead. This will determine the absolute path of the .a file in a portable way and pass that to the linker. The biggest disadvantage of this approach is that the .a file must already be there for the find call to succeed. So if you want to build maths after running the CMake for alpha or build it as part of alpha, this won't work.

  2. Since both libraries are under your control, consider using CMake's packaging mechanism. This is by far the most convenient approach for building, but unfortunately also the most difficult to set up. If you are willing to spend some time digging through the CMake docs and experimenting with the build, I encourage you to give it a try, but if you just want something that works quickly, you might want to stick with option 1.

Upvotes: 5

Related Questions