Build2 – A C++ Build Toolchain and Package Manager
build2.org
build2.org
So I have my Debian setup and I'm happily using apt to install all my software. Now ruby comes along and I need some libraries and have to go and install everything with gem. And I can't use apt to see what gems I have installed and vice versa! Argh!!! Now I have to write some python code and here comes pip... And node/npm... and on and on.
apt-get install libx11-dev is just fine for my C and C++ development needs, thankyouverymuch. I don't see the value in yet another incompatible package manager.
In particular, you get the exact version of the library you want. If you've ever had the experience of trying to make your software work with multiple versions of its dependencies because different OSes ship with different versions, then you'll know how annoying this is.
This is particularly true of run-time problems. If they don't compile, then that's relatively easy to fix. If there's a difference at run-time, its often way more expensive to fix.
With a package manager, you get the exact version, but you also can use different versions for different apps on your system. You can also upgrade without breaking other apps (new security version) or not upgrade if there's some good reason not to.
Isn't this just kicking the can down the road though? The incompatibilities are still something you either have to deal with or users end up with 58 outdated versions of each library and the security vulnerabilities they bring.
> Once you've started using language package managers, it become very apparent that they have huge value, that apt-get doesn't bring.
This is what's wrong with so much modern development, we do what's easy for developers, not what's best for users.
In the client software case, software that works is what's best for users. If you upgrade a library and apps start working, that sucks.
If you're running server-side software, you want dev-production parity, or you can't know it works. So you _need_ to use a package manager. But the same applies to client software: you can't test all these permutations, so you can't even tell it works, and it probably doesn't.
If you're running server side you should have test environments that match prod to be able to catch incompatibilities early.
I work for a company that supports a distribution (SUSE) and I also participate in a distribution's community (openSUSE) and this mentality of "let's just reinvent package management" really does bother me, because it feels like the benefits of having a single package manager for the entire system is being ignored. And this ease of pushing new packages results in a huge amount of small packages so that a standard "hello world" in many frameworks requires something like 700 packages (from a distribution side, that's 700 downstream packages that we now need to curate and maintain).
Don't get me wrong, language package managers do have benefits, but they make life absolute hell for distributions. And distributions having full control of package management definitely brings benefits to users. Rust is the most extreme example, where projects can require a particular version of the nightly build of the compiler. How the hell is a distribution meant to be able to build and ship Rust code in that instance (given that distributions also provide the development tools necessary for working on said projects)? Do we create a new package for every nightly compiler build? How do we curate it?
One of my colleagues gave quite a fair review of the situation and some potential future steps in his talk "Package Managers all the way down"[1]. But bringing this mentality verbatim to C++ is not a step in the right direction IMO.
We've been working with distros on packaging stuff; it's mostly sorted. Each distro is doing the thing that works for them.
Additionally, making sure we play well with other build systems is a big goal this year generally.
Have you worked with openSUSE, since as far as I know devel:languages:rust is still in the state of "we aren't sure how to deal with these problems". In particular, there aren't any rust rpm macros in openSUSE yet, so there doesn't appear to be a clear way to create an rpm for a particular Rust project.
I've written several things in Rust that I would love to package for our distribution, but I just don't know how we are meant to do it without depending on a network connection to download dependencies out-of-band (outside of rpms dependency system).
> Additionally, making sure we play well with other build systems is a big goal this year generally.
Yeah, that's the big problem at the moment. OBS provides huge benefits (rebuilds when dependencies change, tracking of security bugs and fixes) but it also has reasonable restrictions like not being able to connect to the internet.
Having a better story in this respect _really would_ help Rust in its adoption in distributions.
As long as ou have the stuff previously downloaded somewhere, offline builds of everything are totally supported; they're required not only by distros but by Firefox, for example.
A) can't remotely expect anyone to have that installed already B) have no control over the repository or toolchain
If you actually manage to get your library included, then we can compare how long it takes to update your library.
(I've found Bintray to be the easiest.)
How many NPM repos are there? Just one, too-big-to-fail, centralized repository.
Don't ding apt/deb just because people setup their own repos rather than put all the code in the world into one bucket.
There's a lot more inconvenient things than adding the /etc/apt/sources
There are actually plenty, it's just that they're usually found on-prem at a company.
... on Linux.
- not all versions are available, and the versions which are available is different across distributions
- even if the version is the same, the location is not consistent, necessitating search logic to find libraries to link to and headers to include
- even if the version is supposedly the same, the distribution may have enabled different options, fiddled with the package or otherwise made it unsuitable for your use. Upstream developers often loathe to support the version your distribution uses.
- multiple versions cannot be installed independently, and the version you need may conflict with the packages you are using on your system but are not dependencies of your project
- This likewise can cause conflicts between different projects you are working on, causing a need for VMs and projects like vagrant, which are very heavyweight and mean you need to maintain multiple copies of your preferred editor and IDE setup.
- Forking a dependency to fix or customize it (to submit a fix upstream or not) gets even more painful.
All of these are much less painful for language based package managers.
For development purposes, you may want to have the system build everything from source (and/or fetching pre-compiled modules from a build system repository), and output a self-contained tree of local files that you can run.
For release purposes, you can in theory output a package manager package (RPM, .deb, etc.) that contains only your own code's binaries and dependency declarations that the package manager can go satisfy.
There seems to be some degree of integration with build2 (see https://build2.org/faq.xhtml#why-syspkg ) though I don't know how much exactly or whether they go as far as what I'm describing.
Language level dependency managers tend to cover a much wider selection of the extant third party library ecosystem than system level package managers.
I for one don't want to bother with M×N packages.
In addition, "modern CMake" is much better than classic CMake" and the project is improving with such things like CMake server.
I've been writing a simple video game in C++ recently, using CMake to build. I wrote a little bit of code that fetches the few libraries I need in order to have a complete/deterministic build process that works on linux/windows/mac. It lets me change versions (by specifying a new url to a source tarball). Versioned dependency management is so typical and convenient in many other languages and is such a pain in the butt with C++ because CMake is this thing that's sort of good enough. But my CMake experience doesn't compare well at all with maven, pip, gem, cargo, or even npm.
Too many C++ tools couple package management and build which increases their adoption cost and makes it more work to package third part packages. Conan takes the approach of managing dependencies and then giving your build system of choice the information it needs to access those dependencies via conan plugins. I think I had read that the author of Conan was involved in biicode and that the third party packaging problem is what inspired him to create Conan.
Some other cool things about conan
- Can be used for more than C++
- SCM independent
- Artifact caching
- Options allow clients to customize your package (creates distinct artifact)
- Scopes allow developers to modify your build (like conditional build steps so doesn't create a distinct artifact)
Some things I think can be improved
- Needs to separate out dependency lock file like Cargo or Poet
- Build tools need to be packaged in Conan for tracability / reproducibility
- Plugins are in Python which is heavy for deployment and has a large compatibility surface
- Easy to hit limits of declarative dependency files, being forced into implementing them in Python (see above)
- Project templates are hard coded.
Conan does this too. If I follow the instructions to integrate cmake with conan, I would write something like this:
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)
add_executable(timer timer.cpp)
target_link_libraries(timer CONAN_PKG::Poco)
Which now couples my build with conan. If the user would like to pull down the dependencies without conan(ie using apt-get or manually installing them), the cmake build script will not work.Package managers like cget[1] or conda[2] does not couple the build with the package manager. Cget is also serverless which is nice as it can install dependencies from anywhere(even directly from github with `cget install jgm/cmark`), however, you need to setup your own server hosting if you want to install binaries.
http://docs.conan.io/en/latest/integrations/cmake/find_packa...
No need to force me to install Python just to run a build tool.
Many of us only install what we actually need, or what the IT department allows on our images.
I certainly don't want to open a IT ticket to get Python, just to be able to compile random package X.
e: does anyone know if this has any relation to Boost's b2? I know that was originally based off of jam which is not related but the name is so similar I can't help but think I'm missing something :(
I like Ruby more than Python as a language, but I will say that I've never had pip fail to install a dependency on me.
I'm surprised there isn't any part of the gem process that calls `pkg-config`, to verify if a gem will be able to install, given its native dependencies. Having `bundle install` bail out after just a second with "please install libfoo first" would be great, especially for CI.
> I've never had pip fail to install a dependency on me
`pip install` has never failed me, but `pip install --upgrade` fails for me quite a bit. Especially when I try to use it like `gem upgrade`, with a stanza like
pip list --outdated --format=legacy | cut -d' ' -f1 | xargs pip install --upgradehttps://www.cvedetails.com/vulnerability-list/vendor_id-1749...
This is why I've been liking the approach Microsoft has been taking with vcpkg. They clearly see which way the wind is blowing. It's not restricted to using CMake but there is a strong preference for it and it uses CMake as its build scripting system.
I just barely got done trying it on a large project for dependencies and it worked very well overall. A few commands to install a dozen or so dependencies and a quick change to add the vcpkg CMake toolchain so Visual Studio will pass it to CMake. After that and I can just use Open Folder on my CMake project in Visual Studio 2017 and everything just works. It's still a little rough around the edges but vcpkg seems to be developing at a breakneck speed for how new it is.
Dealing with dependencies is the worst part about being a C++ Developer and I'm glad to finally have something that makes it this easy (on one platform at least; I still get to rip my hair out on macOS).
Setting this up was a couple weeks of learning curve but I agree it is worth it to invest in Cmake and also learn the low-level details about how it all fits together since after all we are dealing with a native low-level language, it also pays to see under the hood of these "package managers" and build systems so you can be fluid on any platform where you need to build.
Here is someone who did something similar:
https://crascit.com/2015/07/25/cmake-gtest/
If you're interested I can upload my version a bit later
You can say do things like
"link to these header and this library" - and the modern-er syntax makes that cleaner
but you still can't do a simple
"Get this dependency, build it, then link my current project to it"
To me this is a very strange and frustrating limitation b/c all the necessary piece are already there! It just doesn't have the functionality to call "build it" in the middle like that for some reason. I actually ended up hacking it in (it's like 50 lines of code) but it's a bit ugly and doesn't work recursively
EDIT: It's also very inconvenient to do out-of-source builds with dependencies... constant source of frustration
[0] http://thetoeb.de/2016/08/30/modern-cmake-presentation/
[1] https://www.slideshare.net/DanielPfeifer1/cmake-48475415
And this blog post also has some good stuff:
Is this still in some sort of alpha state with respect to new package submissions? Or is nobody volunteering to maintain the missing packages?
If library devs could start trying those out, it might give it some traction...
Maybe call it cpkg?
Oh dear god no. Can we please have a way more sane manager than a maven of cpp?
Lack of support for binary libraries, specially among projects is a big deal breaker.
Watching the same dependencies being compiled multiple times isn't fun.
Yes, downloading the libraries, placing them in some directory and configuring paths might take some time.
But afterwards, C++ builds are quite fast as they just link to the provided libraries, instead of building the world every single time.
So if project A and B both depend on the same version of lib X, without any change on build flags, lib X will be compiled twice.
In C++ using binary libraries, only liking will occur.
Even if compiling from source is required, build systems like Clearmake allow for sharing object files across projects.
I do expect that Cargo might eventually support such scenarios as well, otherwise it won't be appealing to some of us.
Those two minutes are actually around ten minutes to compile something like rustfmt, just because binary dependencies aren't supported.
My average C++ projects, mixed with Java or .NET code are the ones actually taking two minutes, on the same system.
Truth be told they would take much longer when compiling everything from scratch, but we never do, because we already have the binary libraries.
So it is a bit hard to sell Rust when the toolchain is slower than C++, which I am pretty confident it will certainly improve in any case.
In fact, another company in our corporation has gone the other way, packaging Java dependencies via nuget, and it's also OK.
Why can't people just get over their useless aversion against proven, mature solutions just because it's Java or some nonsense?
GoLang kind of does this (via "go get") and it sucks for multiple reasons:
-you can only distribute packages as source, meaning you need to compile them yourself (this has pros and cons, but it would be nice to be able to distribute binaries if you want)
-your dependencies reference a commit hash, and unless you micromanage your dependencies and constantly look at the github repository's tags, you have no semantic versioning, making it a lot more likely you'll encounter breakages
-there's no way for your dependencies to specify dependencies, unless they're using git submodules (very few projects do), and even with submodules, you can't share dependencies across packages
The list goes on..
Git is for source control. Package managers offer a lot of different (and awesome IMO) features. Lack of package management is one of my biggest gripes with GoLang honestly.