On this article, I’ll undergo the troubles of package deal administration in C/C++ and the way Conan might help you resolve these issues.
Let’s begin with a trivial job, taking values from the command line arguments and printing them to the usual output:
+root
- mainapp.c
- CMakeLists.txt
We use the getops perform from the usual library to get the arguments -a
and -b
and their related values, after which we print them.
Then we use CMake to compile the undertaking into an executable known as myproject
.
Let’s configure this undertaking:
cmake --build ./construct --config Debug --target MyProject -j 10 --
And now let’s run the applying:
./construct/MyProject -a foo -b bar
The output is:
a: foo
b: bar
It works, however ‘works’ isn’t all the time sufficient.
The Getops perform makes use of international variables comparable to optarg
to retailer the arguments related worth, optopt
for the variables identify, and optind
for the index.
Which means that the perform will not be thread secure, and you may solely parse a single enter vector in a single thread.
When you’ve got a number of enter vectors, you have to parse these vectors sequentially, and to make issues worse it’s important to reset the state of the parser each time.
One other well-known downside of getops is the error message that’s internally hidden which makes it troublesome to redirect.
So, to repair this downside, I’ve determined to make use of parg, an open supply C library to parse arguments with thread security by allocating a struct and utilizing it to watch the state of the parser as an alternative of worldwide variables.
Possibility 1. Eat supply code
We are able to use gits submodule tool to clone parg to our undertaking listing after which to make use of cmake to compile and hyperlink it to our executable.
git submodules add https://github.com/jibsen/parg.git
This may create the file .gitsubmodules
with the next content material:
[submodule "parg"]path = pargurl = https://github.com/jibsen/parg.git
Now we will fetch the repo with its supply code:
git submodules init
We now have all of parg
supply code within the parg
listing.
Now we have to add this to our CMakeLists.txt
configurations:
We’ve added the listing and linked the library to our executable.
Now we will change our code to make use of the parg
library:
Now our code is thread secure, and we will simply parse a number of vectors of arguments if wanted.
Let’s compile:
cmake --build ./construct --config Debug --target MyProject -j 10 --
Run:
./construct/MyProject -a foo -b bar
The output is:
a: foo
b: bar
The primary limitation of including the supply code is that we have to compile it each time we compile the executable and this will result in extended compilation instances.
Possibility 2 . Eat compiled library
On this choice, we are going to compile parg
as soon as, save the library, after which hyperlink the library instantly with out compiling it once more.
Having our parg
undertaking compiled will create the file libaprg.a
.
Now we will make some modifications to the CMakeLists and C code to make it work:
CMake:
And now the C code:
The one change to the C code is that now the header file is positioned within the linked library.
Within the CMakeLists file, we’ve eliminated the add_subdirectories
and as an alternative, we’ve linked the compiled library from its path in order that we aren’t going to compile it each time we compile the applying.
Now let’s compile and run once more.
cmake --build ./construct --config Debug --target MyProject -j 10 --
Run:
./construct/MyProject -a foo -b bar
The output is:
a: foo
b: bar
It really works! it’s higher, however it will probably get even higher than that!
The issue with this strategy is that it contaminates the working setting and when you may have many dependencies, and your dependencies have second-tier and even third-tier dependencies, which turns into extraordinarily cumbersome to handle.
Possibility 3. Use Conan for crying out loud!
Conan is an open supply CC++ package deal supervisor developed by JFrog.
It makes use of the JFrog artifactory to handle dependencies.
It’s principally utilized by its Software program as a Service (SaaS) platform, nevertheless it may also be used as a neighborhood repository for inside firm’s wants.
As a prerequisite, you want Python put in.
First, we have to set up Conan from pip utilizing the next command:
pip set up conan
Now we have to create a profile for our configurations:
conan profile new myprofile
The output shall be:
Empty profile created: C:Usersuser.conanprofilesmyprofile
Now we will go to the profile file and set the configurations as we’d like.
In my case, I used the next:
[env]CC=C:/Program Information (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/gcc.exeCXX=C:/Program Information (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/g++.exe[settings]os_build=Home windowsarch_build=x86os=Home windowsarch=x86compiler=gcccompiler.model=8compiler.libcxx=libstdc++11build_type=Launch
This units all of the paths and variables wanted to compile the undertaking.
Having the profile set, now I’ll create conanfile.txt
within the undertaking listing.
Wanting on the parg repository in Conan heart, I can discover all the main points I want.
[requires]
parg/1.0.2[generators]
cmake
Now my undertaking depends on parg
and Conan is aware of this, so it needs to be provisioned for cmake.
Now I can run the Conan set up command:
conan set up . -pr=myprofile
Output:
Configuration:
[settings]
arch=x86
arch_build=x86
build_type=Launch
compiler=gcc
compiler.libcxx=libstdc++11
compiler.model=8
os=Home windows
os_build=Home windows
[options]
[build_requires]
[env]
CC=C:/Program Information (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/gcc.exe
CXX=C:/Program Information (x86)/mingw-w64/i686-8.1.0-posix-dwarf-rt_v6-rev0/mingw32/bin/g++.exe
conanfile.txt: Putting in package deal
Necessities
parg/1.0.2 from 'conancenter' - Cache
Packages
parg/1.0.2:a955db98e980a5ab86ae50d6df8bfee361185c27 - CachePutting in (downloading, constructing) binaries...
parg/1.0.2: Already put in!
conanfile.txt: Generator txt created conanbuildinfo.txt
conanfile.txt: Generator cmake created conanbuildinfo.cmake
conanfile.txt: Aggregating env mills
conanfile.txt: Generated conaninfo.txt
conanfile.txt: Generated graphinfo
Cool!
Now let’s add some modifications to the CMakeLists.txt
file so it’s going to take the library with these dependencies:
So we included the construct data from the sources dir (it was created by the Conan set up) and linked the library.
Now we will use the identical C code we’ve used within the first instance, as proven beneath:
The distinction is that now we don’t pollute our code with git submodules and we gained’t should compile the code each time.
Likewise, we don’t must handle dependencies and artifacts on our personal anymore.
Now let’s compile and run this code once more:
cmake --build ./construct --config Debug --target MyProject -j 10 --
Run:
./construct/MyProject -a foo -b bar
The output is:
a: foo
b: bar
Candy!