Conan by example for C
Tags: c, programming, tutorial, conan
Published: 2023-06-29 19:59:27

As a C developer, you know that many tools exist for managing projects. Every C projects use a subset of these tools, so if you want to use a C library in your project, you should understand how these tools work. If you choose CMake as the build generator of your project, and you want to use a library that uses different build tools like Autotools, you should know how to use Autotools in your CMake file. Conan supports multiple build generators and makes suitable configs based on desired build generator. So, you could select each library that exists in Conan repositories. 
Conan can do more things like:
It is fully decentralized. Users can host their packages on their servers, privately. Integrates with Artifactory and Bintray.
Portable. Works across all platforms, including Linux, OSX, Windows, Solaris, FreeBSD, embedded and cross-compiling, docker, WSL
Manage binaries. It can create, upload and download binaries for any configuration and platform, even cross-compiling, saving lots of time in development and continuous integration. The binary compatibility can be configured and customized. Manage all your artifacts in the same way on all platforms.
Integrates with any build system, including any proprietary and custom one. Provides tested support for major build systems (CMake, MSBuild, Makefiles, Meson, etc).
Extensible: Its Python-based recipes, together with extension points allow for great power and flexibility.
Stable. Used in production by many companies, since 1.0 there is a commitment not to break package recipes and documented behavior.
Read more on its [homepage](https://conan.io/) or [GitHub](https://github.com/conan-io/conan).

## How to install Conan
Python 3.6 or newer is required to install Conan tool. The following commands should run to install it.

```bash
pip install conan
conan profile detect
```
‍‍
If you have installed toolchains, the output of recent command is like:

```ini
gcc>=5, using the major as version
gcc C++ standard library: libstdc++11
Detected profile:
[settings]
arch=x86_64
build_type=Release
compiler=gcc
compiler.cppstd=gnu17
compiler.libcxx=libstdc++11
compiler.version=12
os=Linux

WARN: This profile is a guess of your environment, please check it.
WARN: The output of this command is not guaranteed to be stable and can change in future Conan versions.
WARN: Use your own profile files for stability.
Saving detected profile to /home/amin/.conan2/profiles/default
```

Conan supports http and https proxies. If you want to config proxy, the following variables in GNU/Linux should be set.

```bash
export HTTP_PROXY="http://ip:port"
export HTTPS_PROXY="http://ip:port"
```

## Using Conan
Libraries in the main repository could be accessed by [conan.io](https://conan.io/) or by `conan search <libname>`.  After finding the suitable version of each library, the Conan config file should be configured. Conan supports two different config styles, `conanfile.py` which uses Python to config Conan tool, and `conanfile.txt` which has ini style.

An example is a cli software that gets some options and makes a decision on each option. 
```ini
[requires]
glib/2.73.0

[generators]
CMakeDeps
CMakeToolchain

[options]
glib*:shared=False
```
The conanfile.txt has multiple sections, `requires` section used to define imported libraries with specific version, `generator` section used to define your project's generator like CMake, and `options` section used to config each imported library, for example, `glib*:shared=False` used to compile glib statically. Now it's time to create `CMakefile.txt`. Here is the content of `CMakefile.txt`.
```cmake
cmake_minimum_required(VERSION 3.22.6)
project(net_alert C)

find_package(glib REQUIRED)

include_directories(include)

add_executable(${PROJECT_NAME} src/main.c )

target_link_libraries(${PROJECT_NAME} glib::glib-2.0)
target_link_libraries(${PROJECT_NAME} glib::gio-2.0)
```
Conan makes cmake presets for each library, so `find_package` can find the library. `target_link_libraries` should be used to link with our example. Here is the example code.

```C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <glib/gi18n.h>
#include <gio/gio.h>
static struct config_s {
	gint server_port;
	GString server_ip;
	gboolean server_mode;
	GString wav;
	GString command;
}config;

GString *gbuffer;

static GOptionEntry entries[] =
{
  { "port", 'p', 0, G_OPTION_ARG_INT, &config.server_port, "Server_port", NULL },
  { "destination", 'd', 0, G_OPTION_ARG_STRING, &config.server_ip, "Server ip address", NULL },
  { "server", 's', 0, G_OPTION_ARG_NONE, &config.server_mode, "Server mode", NULL },
  { "wav", 'w', 0, G_OPTION_ARG_STRING, &config.wav, "WAV alert file", NULL },
  { "command", 'c', 0, G_OPTION_ARG_STRING, &config.command, "Command to send to the server", NULL },
  { NULL }
};

int
main(int argc, char **argv) {
	GError *error;
	GOptionContext *context;

	error = NULL;
	wav = g_string_new("alert.wav");
	config.server_mode = FALSE;
	config.server_port = 2986;
	gbuffer = g_string_new(NULL);
	context = g_option_context_new ("net_alert: an application to alert on demand");
	g_option_context_add_main_entries (context, entries, NULL);
	g_option_context_add_group (context, NULL);//gtk_get_option_group (TRUE));
	if (!g_option_context_parse (context, &argc, &argv, &error)){
		g_print("option parsing failed: %s\n", error->message);
		exit(EXIT_FAILURE);
	}
	g_string_overwrite(wav, 0, config.wav.str);
	printf("port: %i\nserver address: %s\nserver mode: %i\nWav: %s\ncommand: %s\n\n"
		, config.server_port
		, (char *)config.server_ip.str
		, config.server_mode
		, wav->str
		, (char *)config.command.str);

	if (config.server_mode)
		server_mode();
	else
		client_mode();
	return 0;
}
```
Conan sets include paths for imported libraries, so header files could be included directly. For a complete version of the example follow the [GitHub repo](https://github.com/khozaei/net_alert).

## Build the example
First of all, Canon must build imported libraries. Then created script `conanbuild.sh` should be sourced by bash shell. After that, CMake can generate build of our example. The following commands needs to build the project.
```bash
conan install . --output-folder=build --build=missing
cd build
source conanbuild.sh
cmake .. -DCMAKE_TOOLCHAIN_FILE=conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Release
cmake --build .
```
## Conclusion
Conan makes C developers happy but, not all libraries are available in main repository of Conan. So, C developers should make their self repository or use libraries with an understanding of more than one build tools.