简体   繁体   中英

CMake - including dependencies inside a static library

I am very new to C++ and all the associated terms and toolchains. I am trying to build a static library that customers can use in their own projects. Ideally, I would like to send them nothing but an .a and a .lib file, plus an .h file.

Right now, my CMake file looks like this:

project(ava-engine-client)
cmake_minimum_required(VERSION 3.9.6)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_FIND_LIBRARY_SUFFIXES .a )

add_compile_options(-std=c++11)

# GRPC and Protocol Buffers libraries location
list(APPEND CMAKE_PREFIX_PATH "/opt/grpc" "/opt/protobuf")

# CMake find modules
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/cmake")


# Recurse and find all the generated Protobuf .cc files
file(GLOB_RECURSE PROTO_GEN_SRCS ${CMAKE_CURRENT_SOURCE_DIR}/ava_engine/ava/*.cc)

include_directories("${CMAKE_CURRENT_SOURCE_DIR}")

# Building the library
add_library(ava_engine_client STATIC src/AvaEngineClient.cc src/AvaEngineClient.h ${PROTO_GEN_SRCS})

target_link_libraries(ava_engine_client ${PROTOBUF_LIBRARIES} ${GRPC_LIBRARY})


## Building Playground
add_executable(playground src/Playground.cc)

target_link_libraries(playground ava_engine_client)

Now this fails at the linking stage, because I don't link the playground target, with the dependencies inside the ava_engine_client library:

Undefined symbols for architecture x86_64:
  "grpc::ClientContext::ClientContext()", referenced from:
      ...
  "grpc::ClientContext::~ClientContext()", referenced from:
      ...
  "grpc::CreateChannel(std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::shared_ptr<grpc::ChannelCredentials> const&)", referenced from:
      ...
  "grpc::g_core_codegen_interface", referenced from:
      ...

This isn't what I want, because it would require the customer to link with dependencies in my library (which doesn't' seem right to me).

Now, I have read a few Stack Overflow posts like this one: ( CMake: include library dependencies in a static library ) that suggest using CMAKE_CXX_ARCHIVE_CREATE to create an archive file. Is this the approach I should take? Is what I want even possible?

If you are bound to create a static library, the solution you linked in your original post is probably the best ( CMake: include library dependencies in a static library ). Using ar or library tools to combine the static libraries seems to be the only way to go. This is a pretty popular question on Stack Overflow and all the answers seem to come down to that.

However, if you are able, the easiest solution by far is to create a shared library and link your static libraries into it (as mentioned by jszpilewski in the comments). Yes, it does mean distributing the shared library for runtime. Whether that is practical or not depends on your project.

The clause add_executable will always try to produce a binary ready to be used by the operating system so it is not suitable for producing a static library.

You may use as an inspiration or even borrow some code from the Google Test unit test framework. It is using CMake to generate the UT framework as configurable static or dynamic libraries using the final syntax like:

cxx_library(gtest "${cxx_strict}" src/gtest-all.cc)

But it defines cxx_library and some other functions internally. So you should take a look at their CMake include file internal_utils.cmake . Google Test comes with the BSD software license.

As stated here :
Add -c option in compiler flags and use it like this:

 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -c")

You have to look at linking step if there's missing some items; maybe a library, or an object file.

The first step in debugging unexpected build failures with CMake generated Makefiles is to run:

 ❯ make VERBOSE=1 

This will give you insight into what CMake is doing behind the scenes.

Ref: Symbol(s) not found for architecture x86_64 - Cmake - Mac sierra

Packing all dependencies into your library may be tempting at first, because it should result in the highest compatibility for your users. Often, though, it's not such a good idea because also the size of your library can grow very quickly. You also need to make sure to have a proper static library, ie, you would need to cram in all the typical system libraries that come with every C or C++ installation. Otherwise there might be incompatibilites further down the road.

If you compile a static library you should also use -fPIC to allow your library to be used within other shared libraries or binaries:

set_target_properties(ava_engine_client PROPERTIES POSITION_INDEPENDENT_CODE on)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM