1

I have created a "self-contained" C++ shared library that uses two additional libraries, namely OpenCL and Boost C++. I used CMake for this purpose.

Ideally, the library would be self-contained, i.e., external applications would not have to be explicitly linked to OpenCL and Boost. Instead they would just link to my library.

However, compiling an external application with g++ (and not using CMake) requires that the user is aware of the location of the header files, for both OpenCL and Boost, in addition to specifying them explicitly (with -I*sub/library/path*).

Is there a way to make CMake generate a library that encloses the paths for the headers that belong to the sub-libraries? This way the user would just have to link to my library and not be responsible for providing the file path for the sub-library headers.

Thanks

rjmarques
  • 369
  • 1
  • 3
  • 10
  • 5
    If users do not need to use OpenCL or Boost headers directly, they shouldn't be included in the interface to your library (i.e. in your headers). Move those `#include`s into the implementation files instead. That way users `#include`ing *your* headers don't need to point their compilers at the other library paths too. – tmpearce Oct 07 '12 at 15:30
  • Some of my library's API functions have OpenCL structures as input/output. Therefore, the OpenCL includes have to be defined in the headers. The user only calls functions that do not have external library structural declarations, since the previous API functions are protected. – rjmarques Oct 07 '12 at 15:36
  • 3
    Ideally, you should rewrite your API functions to accept your own structures as input/output and convert internally to OpenCL. There is no other way. – André Oct 08 '12 at 06:33
  • Wrapping around the external structures, of both OpenCL and Boost, is an added complexity that does not directly fix the problem. The wrappers would still be defined in the headers (or so they should be), and thus the #includes would still be present in the headers. Moreover, some of my objects have members that are either Boost or OpenCL structures. Therefore, these member declarations would also have to be remited to the source files (following in tmpearce's suggestion). However, remiting variable declaration to the source file is not a good practice (IMO). – rjmarques Oct 08 '12 at 10:42
  • 1
    I do agree with Andre: the only way to truly be independent is if the caller of your library really never can tell that you are using Boost or OpenCL. That does mean no inclusion of library header files of either - you'll have to have an internal header file that contains the specifics and an external header file that just contains your generalised interface. However, it seems to me you are not willing to go that far... – Klaas van Gend Oct 08 '12 at 12:52
  • 2
    You can avoid having the headers for your wrappers exposing OpenCL or Boost headers by having your wrappers use the PIMPL idiom. – drescherjm Oct 08 '12 at 12:55
  • The PIMPL idiom seems like a good solution. It does, however, seem a bit akward to wrap every used simple external structure (e.g., cl_event, cl_command_queue, mutex, condition). Regardless, I thank you all for your help. – rjmarques Oct 08 '12 at 16:33

1 Answers1

0

For anyone using CMake with targets, you can do this by specifying OpenCL and Boost as PUBLIC or INTERFACE link libraries of your library like so:

target_link_libraries(my_library PUBLIC OpenCL::OpenCL Boost::Boost)

The docs for target_link_libraries state:

The PUBLIC, PRIVATE and INTERFACE keywords can be used to specify both the link dependencies and the link interface in one command. Libraries and targets following PUBLIC are linked to, and are made part of the link interface. Libraries and targets following PRIVATE are linked to, but are not made part of the link interface. Libraries following INTERFACE are appended to the link interface and are not used for linking <target>.

Not only will link flags be made transitive for INTERFACE_LINK_LIBRARIES, but also target include directories (as long as those include directories were also specified as PUBLIC or INTERFACE when associated with the dependency target with target_include_directories.)

Note: I think you will need to do some extra work if you want to handle installation. See this post by @Lucas Guesser.

starball
  • 20,030
  • 7
  • 43
  • 238