The Zen of integrating 3rd party packages

I’m updating my build chain (new compilers, updated 3rd party versions and such) and I want to clean up some of the cruft of our original naive implementations.

I have at least 3 different ways external packages are integrated, and I’d like to enforce some consistency. One of my least supported approaches was a package called mpsse. Previously, I downloaded the .tar.gz file, unpacked it out of my project, modified the Makefile to get it to compile, and installed it in my VM.

Now, I want to build it as part of my project. I added the modified source tree to my git repo in external (a new directory I created for the 3rd party packages).

The CMakeLists.txt file in external looks like this:

include(ExternalProject)

# MPSSE
ExternalProject_Add(mpsse
  # download step -- skipped since it is here
  DOWNLOAD_COMMAND ""
  SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/libmpsse-1.3/src
  # configure step
  CONFIGURE_COMMAND <SOURCE_DIR>/configure --disable-python
  # build step
  BUILD_IN_SOURCE 1
  BUILD_COMMAND make
  # install step -- don't install it; just use it
  INSTALL_COMMAND ""
)

This seems to build fine.

When I try to use it in another CMakeLists.txt file, like this:

target_link_libraries( ${myTarget}
  mpsse -lftdi1 -lusb-1.0
)

I get an error:

CMake Error at src/gpio/CMakeLists.txt:30 (target_link_libraries):
  Target "mpsse" of type UTILITY may not be linked into another target.  One
  may link only to INTERFACE, OBJECT, STATIC or SHARED libraries, or to
  executables with the ENABLE_EXPORTS property set.

Clearly I’m missing something, but I don’t know how to properly integrate this thing into my project. I’m open to anything, no matter how invasive. Now is the time to get this right (and learn a thing or two in the process)

Clarification
I ran CMake before changing the dependent target, and the external project built fine. Once I made mpsse a dependency of another project, CMake is no longer happy. So I’m still broken, but not the way I thought I was.

Similar To Intended way to interface with external targets(?)

So I guess Zen will have to wait. As my favorite fortune cookie says,

Pragmatics must take precedence over elegance, for Nature is not impressed.

I was trying to avoid actually installing this project, because that’s kind of destructive. Everything else I’ve built in CMake, I can just use within my project. But, since I’m building in a Docker container, I can tolerate it, and the project must move forward.

This got me working:

include(ExternalProject)


# MPSSE
ExternalProject_Add(mpsse
  DOWNLOAD_DIR mpsse
  SOURCE_DIR mpsse/libmpsse-1.3/src
  INSTALL_DIR /usr/local

  # download step
  DOWNLOAD_COMMAND unzip -u ${CMAKE_CURRENT_SOURCE_DIR}/libmpsse-1.3.zip

  # configure step
  CONFIGURE_COMMAND <SOURCE_DIR>/configure --disable-python --prefix <INSTALL_DIR> --libdir <INSTALL_DIR>/lib64

  # build step
  BUILD_IN_SOURCE 1
  BUILD_COMMAND make
)

I had to explicitly do the unzip because if I just pass a URL, CMake insists on adding intervening directories in the <SOURCE_DIR> path. With the explicit unzip I had more control. The challenge with this particular build is that the zipfile has an enclosing directory that has doc and src subdirectories. I couldn’t figure out how to get configure to run in the same directory it is in. When I controlled <SOURCE_DIR>, it worked.

I’d like to understand the proper way to expose the products of this build for CMake, but I think in the long run, I’ll be better off just writing a CMake file for it. It’s a trivial project and that would probably have been less work than this has cost me.

Cc: @craig.scott