How to specify library dependency introduced by he

2019-02-21 00:57发布

Suppose in a CMake project, I have a source that is built into a library

// a.cpp
void f() { /* some code*/ }

And I have a header

// b.h
void f();
struct X { void g() { f(); } };

I have another file:

// main.cpp
#include "b.h"
int main() { X x; x.g(); }

The CMakeLists.txt contains:

add_library(A a.cpp)
add_executable(main main.cpp)
target_link_libraries(main A)

Now look at the last line of the CMakeLists.txt: I need to specify A as the dependencies of main explicitly. Basically, I need to specify such dependencies for every source that includes b.h. Since the includes can be indirect and go all the way down through a chain of includes. For example, a.cpp calls a class inline function of c.h, which in turns calls function in d.h, etc, and finally calls function from library A. If b.h is included by lots files, manually finding out all such dependencies is not feasible for large projects.

So my question is, is there anyway to specify that, for every source file that directly or indirectly includes a header, it needs to link against certain library?

Thanks.

1条回答
该账号已被封号
2楼-- · 2019-02-21 01:54

To make one thing clear: You a.cpp gets compiled into a lib "A". That means that any user of A, will need to specify target_link_libraries with A. No way around it. If you have 10 little applications using A, you will need to specify target_link_libraries ten times.

My answer deals with the second issue of your question and I believe it is the more important one:

How to get rid of a chain of includes?

By including a.h in b.h and using its method in b.h you are adding a "implicit" dependency. As you noticed, any user of b.h needs a.h as well. Broadly speaking, there are two approaches.

The good approach:

This has nothing to do with CMake, but is about encapsulation. The users of your library (incl. you yourselves) should not need to worry about its internal implementation. That means: Don't include b.h in a.h.

Instead, move the include to a .cpp file. This way, you break the chain. E.g. something like

// b.h
void f();
struct X
{ 
    void g();
};

// b.cpp
#include b.h
#include a.h
void X::g( )
{
    f();
}

This way, the use of a.h is "contained" in the cpp file and anyone using you library need only include b.h and link to b.lib.

The alternative:

Now, there are situations where you have to accept such a "dependency" or where it is a conscious choice. E.g. when you have no control over A or when you conciously decided to create a library defined in terms of classes/structs internal to A.

In that case, I suggest you write a piece of CMake code, which prepares all the necessary include-dirs down the chain. E.g. define a variable "YOURLIB_INCLUDES" and "YOURLIB_LIBRARIES" in "YourLibConfig.cmake" and document that any user of your library should import "YourLibConfig.cmake". This is the approach several cmake-based projects take. E.g. OpenCV installs a OpenCVConfig.cmake file, VTK installs a VTKConfig.cmake and prepares a UseVTK.cmake file

查看更多
登录 后发表回答