I last did serious C/C++ development in 1999 while at GS, but since C++11 came out and
Bjarne Stroustrup came to work for Morgan Stanley I have wanted to pick it up again. One of the obstacles was that not only was my knowledge of the language out of date, but so was my knowledge of the development tools and build systems.
Since I use PyCharm and IntelliJ IDEA for Python and Java it made sense to use CMake and CLion at least to start. Since I wanted to make use of some existing libraries the only thing then was to find a way to integrate open source libraries into the build.
In the Java world you have Maven; Perl has CPAN; R has CRAN; Python has pip; etc. -- given the profusion of open source libraries a good package manager can help simplify builds and make it easier to set up a new development machine, something particularly important since my targets will be Linux VM but I mostly work on MacOS. I ended up stumbling on Conan, which seemed to fit the bill.
Conan the Librarian
Conan is itself written in Python and can be set up on multiple platforms with pip install conan
. It supports a text descriptor with dependencies, but the real power is in writing your package definitions in Python using a conaninfo.py
file -- you have a full-featured scripting language to manipulate the dependencies, customize the build by platform, etc..
I started with LibUV and LibWebsockets (LWS). The latter depends on OpenSSL, zlib and (optionally) LibUV. Kyle Maxwell had initial attempts at both in GitHub which I hope to merge back to later.
The conaninfo.py
starts with metadata declarations:
class LibuvConan(ConanFile):
name = "LibUV"
description = "LibUV asynchronous I/O framework"
version = "1.9.1"
license = "Apache Software License 2.0"
author = "Kyle Downey"
url = "https://github.com/kyle-downey/conan-libuv"
The next block defines settings, where I hit an issue with CLang version:
settings = {
"os": ["Linux", "Macos"],
"compiler": None,
"build_type": None,
"arch": None
}
Despite repeated attempts builds kept breaking because the default compiler version was 7.3 but I had CLang 8.0.0 installed. What I learned along the way was that the keys in the above hash are used to constrain the available variables, and they get overlaid with ~/.conan/settings.yml
and conan.conf
. Essentially: settings.yml has all supported values; conan.conf has your local installation's defaults; and the conanfile.py can choose to limit to a subset, e.g. os is being limited to the two platforms I have been able to test: Linux & MacOS. (Any key set to None
will allow all supported values.)
The problem arose because I installed conan and then upgraded XCode to 8.0. The version I had at the time (7.3) got baked into conan.conf, breaking the LWS build, which checked to see if CLang's major.minor version matched settings.compiler.version
for the compiler key apple-clang
... and it did not.
Customizing the build
The lifecycle of a package maps more or less 1:1 to methods in conaninfo.py
-- something that Conan's documentation could maybe do a bit better explaining, as I ended up having to read quite a bit of the code to understand what was called when (and to be honest still am a bit unclear, as it seems the callbacks differ during a remote install vs. a build).
The key methods:
config_options
lets you mutate settingssource
gets called inconan source
and downloads source code from GitHub or elsewhere for builds from sourcebuild
executes the build from source -- the documentation covers various options here
def config_options(self):
# ...
def source(self):
# ...
def build(self):
# ...
def package(self):
# ...
def package_info(self):
# ...
e.g. you can add dependencies:
def config_options(self):
self.requires.add("OpenSSL/1.0.2i@lasote/stable")
self.requires.add("LibUV/1.9.1@cloudwall/stable")
Testing the build
You can install your conaninfo.py locally
# do all the building in a temporary directory
mkdir build
cd build
# run relative to parent directory
conan install .. -g env
conan source ..
conan build ..
# prepare and upload
conan export cloudwall/stable
conan upload LibWebsockets/1.2@cloudwall/stable
The last two commands package up the source and deploy to conan.io's repository. This requires a user ID and password (cloudwall in my case). If everything succeeds you'll get your include and lib directories under your local repository in ~/.conan/data
.
Wrapping up
Full code on Github:
and the library definitions are also available on Conan now. Just run:
conan install LibWebsockets/2.1@cloudwall/stable --build LibUV --build LibWebsockets
and it will build and install the dependencies in your local cache.