Conan 1.46: New XcodeToolchain and XcodeBuild tools, improved conf system, new helpers for Git.
We are pleased to announce that Conan 1.46 has been released and brings some significant
new features and bug fixes. We have improved Xcode support by adding a new
XcodeToolchain
generator and a
XcodeBuild
build helper tool that complement the
XcodeDeps
generator introduced in Conan
1.42. Also, the Conan
configuration
system has been
significantly improved, allowing a more powerful manipulation of the Conan “conf” in
profiles and recipes and adding jinja2 template syntax support. Also, we added new
helpers for Git, for direct use in the export()
method to capture git URL and commit,
and in the source()
method to clone and checkout a git repository.
New XcodeBuild and XcodeToolchain tools
Now you can use XcodeToolchain and XcodeBuild new helpers, along with XcodeDeps, to build your Xcode projects in Conan recipes. Let’s see how to create a package that uses the Xcode build system. Imagine you have generated a simple “hello world” library project in Xcode that you want to package with Conan and it has this structure:
├── HelloLibrary.xcodeproj
└── src
├── hello.cpp
└── hello.hpp
You could easily create a Conan package for this library using a conanfile.py
like this
one that uses XcodeBuild for building the library and XcodeToolchain to pass
information from the Conan settings to the Xcode build system:
import os
from conan import ConanFile
from conan.tools.apple import XcodeBuild
from conan.tools.files import copy
class HelloLib(ConanFile):
name = "hello"
version = "1.0"
settings = "os", "compiler", "build_type", "arch"
generators = "XcodeToolchain"
exports_sources = "HelloLibrary.xcodeproj/*", "src/*"
def build(self):
xcode = XcodeBuild(self)
xcode.build("HelloLibrary.xcodeproj")
def package(self):
copy(self, "*/libhello.a", src=self.build_folder,
dst=os.path.join(self.package_folder, "lib"),
keep_path=False)
copy(self, "src/hello.hpp", src=self.build_folder,
dst=os.path.join(self.package_folder, "lib"),
keep_path=False)
def package_info(self):
self.cpp_info.libs = ["hello"]
Before creating the package, you have to add the Conan generated .xcconfig files to the Xcode project. Let’s generate them for Release and Debug configurations:
$ conan install . -s build_type=Release
$ conan install . -s build_type=Debug
Add the generated .xcconfig files to the Xcode project, and in the Info/Configurations section, choose conan_config for both configurations
Now, you can create the library for both Debug and Release configurations:
$ conan create . -s build_type=Debug
$ conan create . -s build_type=Release
When Conan executes the build()
method, the XcodeBuild helper invokes the Xcode
build system to build the library. Please check the documentation for the full reference
of
XcodeToolchain,
XcodeBuild
and
XcodeDeps.
Improved “conf” system
There are a couple of things that have been improved in the Conan configuration system:
-
Support for jinja2 templates in the
global.conf
configuration file. This can be useful for example to set the parallel build jobs number to a value defined by the system configuration:... # Using all the cores automatically tools.build:jobs={{os.cpu_count()}} ...
Python os
and system
modules are available in the template context.
- Support for different data types in the configuration. Now you can use Python data types
when setting configuration values. Conan will interpret those using the Python built-in
eval()
function. You can use strings, booleans, integers, lists and dictionaries. For example:
# String
tools.microsoft.msbuild:verbosity=Diagnostic
# Boolean
tools.system.package_manager:sudo=True
# Integer
tools.microsoft.msbuild:max_cpu_count=2
# List of values
user.myconf.build:listvalue=["value1", "value2"]
# Dictionary
tools.microsoft.msbuildtoolchain:compile_options={"ExceptionHandling": "Async"}
- New operators for configuration values in profiles. You can use those to prepend (
=+
), append (+=
) or reset (=!
) configuration values inside the[conf]
section of your profiles.
[settings]
...
[conf]
# Define the value => ["value1"]
user.myconf.build:listvalue=["value1"]
# Append the value ["value2"] => ["value1", "value2"]
user.myconf.build:listvalue+=["value2"]
# Prepend the value ["value0"] => ["value0", "value1", "value2"]
user.myconf.build:listvalue=+["value0"]
# Unset the value
user.myconf.build:listvalue=!
- New methods available in the
conf_info
object to manipulate configuration values in recipes. You can use different methods to get, define or manipulate configuration values:
import os
from conans import ConanFile
class Pkg(ConanFile):
name = "pkg"
def package_info(self):
# Setting values
self.conf_info.define("tools.microsoft.msbuild:verbosity", "Diagnostic")
# Getting values
self.conf_info.get("tools.microsoft.msbuild:verbosity") # == "Diagnostic"
# Modifying configuration list-like values
self.conf_info.append("user.myconf.build:listvalue", "value1")
For the full reference of available methods, please check the Conan documentation.
New conan.tools.scm.Git tool
There is a new tool
available in
Conan to manage git repositories in the conan.tools.scm module
. With this tool, recipes
can add the same functionality that the scm
feature
provided but more flexibly and explicitly (note that the scm feature will be
removed in Conan 2.0).
Let’s see an example of how to use the new helper. We can take the previous recipe we used to define our Xcode package that had this structure:
├── conanfile.py
├── HelloLibrary.xcodeproj
└── src
├── hello.cpp
└── hello.hpp
We will change the recipe to get the sources from a git repository. The new recipe could look like this:
import os
from conan import ConanFile
from conan.tools.apple import XcodeBuild
from conan.tools.files import copy
from conan.tools.scm import Git
from conan.tools.files import update_conandata
class HelloLib(ConanFile):
...
def layout(self):
self.folders.source = "."
def export(self):
git = Git(self, self.recipe_folder)
scm_url, scm_commit = git.get_url_and_commit()
# we store the current URL and commit in conandata.yml
update_conandata(self, {"sources": {"commit": scm_commit, "url": scm_url}})
def source(self):
# we recover the saved URL and commit from conandata.yml
git = Git(self)
sources = self.conan_data["sources"]
# get the sources from the URL and commit
git.clone(url=sources["url"], target=".")
git.checkout(commit=sources["commit"])
def build(self):
xcode = XcodeBuild(self)
xcode.build("HelloLibrary.xcodeproj")
...
The most important parts are defined in the export()
and source()
methods of the conanfile:
-
In the
exports()
method we use theget_url_and_commit()
to get the current commit and URL for the git repository. Then theupdate_conandata()
helper is used to save this information inside theconandata.yml
file in the cache along with the recipe. -
In the
source()
method we retrieve the information we stored in theconandata.yml
file to clone the repository URL and checkout the commit.
As you can see this way of interacting with git repositories in Conan recipes is very flexible and explicit. If you want to check the complete set of methods available for the Git tool, please check the Conan documentation.
Besides the items listed above, there were some minor bug fixes you may wish to read about. If so please refer to the changelog for the complete list.
We hope you enjoy this release, and look forward to your feedback.