Managing transitive dependencies with Conan and CMake
  • January 06, 2020 by Kai Wolf

Back when I looked into Conan the first time in 2017 the state-of-the-art for dependency management in the C and C++ software development world consisted of building everything from scratch and checking all binary artifacts into version control or something similar along the line. Fortunately, this seems to be changing now with the raise of a proper package dependency management solution for C and C++.

However, no software is free of bugs and the same holds true for Conan as well. Back then, when I’ve tried to model a simple, single dependency for a project, this tool has failed me as it wasn’t able to resolve transitive dependencies. This issue in particular has since been resolved, but managing several, inter-depending software packages in a given project using Conan and CMake still challenging.

I’ve recently produced and published a specially configured VTK package for a medical project I’ve worked on for a client. For this I’ve setup VTK that it uses another (Conan) package, published by me. Thus, both dependencies (VTK and TBB in this case) were both distributed using Conan and the first one was depending on the second one. Both dependencies are using CMake for managing their build system. However, in VTK’s CMake configuration there is a slight imperfection as it doesn’t simply link against TBB as yet another logical build target, but it tries to resolve this dependency in a dedicated FindTBB.cmake script file. This eventually leads to hard coded paths in the VTK package as-is when it gets build on a dedicated server. Obviously, this will not work when this package gets consumed by a client due to the hard coded path references that will most certainly be different on any other machine.

The fix for this is either trying to patch VTK’s CMake configuration file, which may takes a while or won’t even be accepted upstream, or swapping the hard coded paths to TBB with a reference to where Conan put the TBB dependency. This can be done as follows:

def cmake_fix_tbb_dependency_path(self, file_path):
    with open(file_path, 'r') as file:
        file_data = file.read()

    if file_data:
        # Replace the target string
        tbb_root = self.deps_cpp_info["tbb"].rootpath.replace('\\', '/')
        file_data = re.sub(tbb_root, r"${CONAN_TBB_ROOT}", file_data, re.M)

        with open(file_path, 'w') as file:
            file.write(file_data)

This fix will be sufficient for my use case, as I can ensure that both packages will be consumed from Conan. That being said, this is far from a common solution for these types of problems. Furthermore, In my experience these types of issues will come up from time to time and fortunately in this case it happened for a rather simple transitive dependency chain that wasn’t that hard to debug and fix. I can imagine though, that things do look a bit different as soon as the number of (inter connected) dependencies do increase.

There will be a Conan conference in March this year that I’m planning to attend. I really appreciate the patience and effort of the people that are actively working on Conan and hopefully and I’ll be able to address a few open issues I have with this tool as well.

I’m available for software consultancy, training and mentoring. Please contact me, if you are interested in my services.