diff --git a/creating_packages/getting_started.rst b/creating_packages/getting_started.rst index 92545a4a562..6356cb588d6 100644 --- a/creating_packages/getting_started.rst +++ b/creating_packages/getting_started.rst @@ -1,377 +1,225 @@ .. _packaging_getting_started: -Getting Started +Getting started =============== -To start learning about creating packages, we will create a package from the existing source code -repository: https://github.com/conan-io/hello. You can check that project, it is a very simple -"hello world" C++ library, using CMake as the build system to build a library and an executable. It does not contain -any association with Conan. +This section introduces how to create your own Conan packages, explain *conanfile.py* recipes and the commands to build +packages from sources in your computer. -We are using a similar GitHub repository as an example, but the same process also applies to other source -code origins, like downloading a zip or tarball from the internet. -.. note:: +.. important:: - For this concrete example you will need, besides a C++ compiler, both *CMake* and *git* - installed and in your path. They are not required by Conan, so you could use your own build system - and version control instead. + This is a **tutorial** section. You are encouraged to execute these commands. + For this concrete example, you will need **CMake** installed in your path. + It is not strictly required by Conan to create packages, you can use + other build systems (as VS, Meson, Autotools and even your own) to do that, without any dependency + to CMake. + Some of the features used in this section are **experimental**, like ``CMakeToolchain`` or ``cmake_layout()``, + and they might change in future releases. There are other alternative tools that are stable, please check + the :ref:`reference section` for more information. -Creating the Package Recipe ---------------------------- -First, let's create a folder for our package recipe, and use the :command:`conan new` helper command that -will create a working package recipe for us: +Using the :command:`conan new` command will create a "Hello World" C++ library example project for us: .. code-block:: bash - $ mkdir mypkg && cd mypkg - $ conan new hello/0.1 -t + $ mkdir hellopkg && cd hellopkg + $ conan new hello/0.1 --template=cmake_lib + File saved: conanfile.py + File saved: src/CMakeLists.txt + File saved: src/hello.cpp + File saved: src/hello.h + File saved: test_package/conanfile.py + File saved: test_package/src/CMakeLists.txt + File saved: test_package/src/example.cpp -This will generate the following files: -.. code-block:: text +The generated files are: - conanfile.py - test_package - CMakeLists.txt - conanfile.py - example.cpp +- **conanfile.py**: On the root folder, there is a *conanfile.py* which is the main recipe file, responsible for defining how the package is built and consumed. +- **src** folder: the *src* folder that contains the simple C++ "hello" library with a simple generic *CMakeLists.txt* to build it, with nothing specific about Conan in it. +- (optional) **test_package** folder: contains an *example* application that will require and link with the created package. + It is not mandatory, but it is useful to check that our package is correctly created. -On the root level, there is a *conanfile.py* which is the main recipe file, responsible for -defining our package. Also, there is a *test_package* folder, which contains a simple example -consuming project that will require and link with the created package. It is useful to make sure -that our package is correctly created. - -Let's have a look at the root package recipe *conanfile.py*: +Let's have a look at the package recipe *conanfile.py*: .. code-block:: python - from conans import ConanFile, CMake, tools + from conans import ConanFile + from conan.tools.cmake import CMakeToolchain, CMake + from conan.tools.layout import cmake_layout class HelloConan(ConanFile): name = "hello" version = "0.1" - license = "" - url = "" - description = "" + + # Binary configuration settings = "os", "compiler", "build_type", "arch" - options = {"shared": [True, False]} - default_options = {"shared": False} - generators = "cmake" - - def source(self): - self.run("git clone https://github.com/conan-io/hello.git") - # This small hack might be useful to guarantee proper /MT /MD linkage - # in MSVC if the packaged project doesn't have variables to set it - # properly - tools.replace_in_file("hello/CMakeLists.txt", "PROJECT(MyHello)", - '''PROJECT(MyHello) - include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) - conan_basic_setup()''') + options = {"shared": [True, False], "fPIC": [True, False]} + default_options = {"shared": False, "fPIC": True} + + # Sources are located in the same place as this recipe, copy them to the recipe + exports_sources = "src/*" + + def config_options(self): + if self.settings.os == "Windows": + del self.options.fPIC + + def layout(self): + cmake_layout(self) + + def generate(self): + tc = CMakeToolchain(self) + tc.generate() def build(self): cmake = CMake(self) - cmake.configure(source_folder="hello") + cmake.configure() cmake.build() - # Explicit way: - # self.run('cmake %s/hello %s' - # % (self.source_folder, cmake.command_line)) - # self.run("cmake --build . %s" % cmake.build_config) - def package(self): - self.copy("*.h", dst="include", src="hello") - self.copy("*hello.lib", dst="lib", keep_path=False) - self.copy("*.dll", dst="bin", keep_path=False) - self.copy("*.so", dst="lib", keep_path=False) - self.copy("*.dylib", dst="lib", keep_path=False) - self.copy("*.a", dst="lib", keep_path=False) + cmake = CMake(self) + cmake.install() def package_info(self): self.cpp_info.libs = ["hello"] -This is a complete package recipe. Without going into detail, these are the -basics: - -- The ``settings`` field defines the configuration of the different binary packages. In - this example, we defined that any change to the OS, compiler, architecture or build type will - generate a different binary package. Please note that Conan generates different binary packages for - different introduced configuration (in this case settings) for the same recipe. - - Note that the platform on which the recipe is running and the package being built differ from - the final platform where the code will be running (``self.settings.os`` and ``self.settings.arch``) if - the package is being cross-built. So if you want to apply a different build depending on the current - build machine, you need to check it: - .. code-block:: python +Let's explain a little bit this recipe: - def build(self): - if platform.system() == "Windows": - cmake = CMake(self) - cmake.configure(source_folder="hello") - cmake.build() - else: - env_build = AutoToolsBuildEnvironment(self) - env_build.configure() - env_build.make() +- The binary configuration is composed by ``settings`` and ``options``. See more in :ref:`this section`. + When something changes in the configuration, the resulting binary built and packaged will be different: - Learn more in the :ref:`Cross building ` section. + - ``settings`` are project wide configuration, that cannot be defaulted in recipes, like the OS or the + architecture. + - ``options`` are package specific configuration and can be defaulted in recipes, in this case we + have the option of creating the package as a shared or static library, being static the default. -- This package recipe is also able to create different binary packages for static and shared - libraries with the ``shared`` option, which is set by default to ``False`` (i.e. by default it will use - static linkage). +- The ``exports_sources`` attribute defines which sources are exported together with the recipe, these + sources become part of the package recipe (there are other mechanisms that don't do this, will be explained + later. -- The ``source()`` method executes a :command:`git clone` to retrieve the sources from Github. Other - origins, such as downloading a zip file are also available. As you can see, any manipulation of the - code can be done, such as checking out any branch or tag, or patching the source code. In this example, - we are adding two lines to the existing CMake code, to ensure binary compatibility. Don't worry - about it now, we'll deal with it later. +- The ``config_options()`` method (together with ``configure()`` one) allows to fine tune the binary configuration + model, for example, in Windows there is no ``fPIC`` option, so it can be removed. -- The ``build()`` configures the project, and then proceeds to build it using standard CMake commands. The - ``CMake`` object just assists to translate the Conan settings to CMake command line - arguments. Please note that **CMake is not strictly required**. You can build packages directly - by invoking **make**, **MSBuild**, **SCons** or any other build system. +- The ``generate()`` method prepares the build of the package from source. In this case, it could be simplified + to an attribute ``generators = "CMakeToolchain"``, but it is left to show this important method. In this case, + the execution of ``CMakeToolchain`` ``generate()`` method will create a *conantoolchain.cmake* file that maps + the Conan ``settings`` and ``options`` to CMake syntax. - .. seealso:: Check the :ref:`existing build helpers `. +- The ``build()`` method uses the ``CMake`` wrapper to call CMake commands, it is a thin layer that will manage + to pass in this case the ``-DCMAKE_TOOLCHAIN_FILE=conantoolchain.cmake`` argument. It will configure the + project and build it from source. - The ``package()`` method copies artifacts (headers, libs) from the build folder to the final - package folder. + package folder. It can be done with bare "copy" commands, but in this case it is leveraging the already + existing CMake install functionality (if the CMakeLists.txt didn't implement it, it is easy to write ``self.copy()`` + commands in this ``package()`` method. -- Finally, the ``package_info()`` method defines that the consumer must link with the "hello" library +- Finally, the ``package_info()`` method defines that consumers must link with a "hello" library when using this package. Other information as include or lib paths can be defined as well. This - information is used for files created by generators to be used by consumers, as - *conanbuildinfo.cmake*. - -.. note:: - - When writing your own *conanfile.py* references, please bear in mind that you should follow the rules in - :ref:`conanfile_reference` - -The test_package Folder ------------------------ - -.. note:: - - The **test_package** differs from the library unit or integration tests, which should be - more comprehensive. These tests are "package" tests, and validate that the package is properly - created, and that the package consumers will be able to link against it and reuse it. - -If you look at the ``test_package`` folder, you will realize that the ``example.cpp`` and the -``CMakeLists.txt`` files don't have unique characteristics. The *test_package/conanfile.py* file is just -another recipe, that can be perceived as a consumer *conanfile.txt* that has been displayed in -previous sections: - -.. code-block:: python - - from conans import ConanFile, CMake - import os - - class HelloTestConan(ConanFile): - settings = "os", "compiler", "build_type", "arch" - generators = "cmake" - - def build(self): - cmake = CMake(self) - cmake.configure() - cmake.build() + information is used for files created by generators (as ``CMakeDeps``) to be used by consumers. Although + this method implies some potential duplication with the build system output (CMake could generate xxx-config.cmake files), + it is important to define this, as Conan packages can be consumed by any other build system, not only CMake. - def imports(self): - self.copy("*.dll", dst="bin", src="bin") - self.copy("*.dylib*", dst="bin", src="lib") - def test(self): - os.chdir("bin") - self.run(".%sexample" % os.sep) +The contents of the ``test_package`` folder is not critical now for understanding how packages are created, the important +bits are: -The *conanfile.py* described above has the following characteristics: +- ``test_package`` folder is different from unit or integration tests. These tests are "package" tests, and validate that the package is properly + created, and that the package consumers will be able to link against it and reuse it. +- It is a small Conan project itself, it contains its own ``conanfile.py``, and its source code including build scripts, that depends on + the package being created, and builds and execute a small application that requires the library in the package. +- It doesn't belong to the package. It only exist in the source repository, not in the package. -- It doesn't have a name and version, as we are not creating a package so they are not - necessary. -- The ``package()`` and ``package_info()`` methods are not required since we are not creating a - package. -- The ``test()`` method specifies which binaries need to run. -- The ``imports()`` method is set to copy the shared libraries to the ``bin`` folder. When - dynamic linking is applied, and the ``test()`` method launches the ``example`` executable, they are - found causing the ``example`` to run. -.. note:: - An important difference with respect to standard package recipes is that you don't have - to declare a ``requires`` attribute to depend on the tested ``hello/0.1@demo/testing`` package - as the ``requires`` will automatically be injected by Conan during the run. However, if you choose to - declare it explicitly, it will work, but you will have to remember to bump the version, - and possibly also the user and channel if you decide to change them. - -.. _creating_and_testing_packages: - -Creating and Testing Packages ------------------------------ - -You can create and test the package with our default settings simply by running: +Let's build the package from sources with the current default configuration (default profile), and then let the ``test_package`` folder test the package: .. code-block:: bash $ conan create . demo/testing ... - Hello world Release! + hello/0.1: Hello World Release! + hello/0.1: _M_X64 defined + ... -If "Hello world Release!" is displayed, it worked. +If "Hello world Release!" is displayed, it worked. This is what has happened: -The :command:`conan create` command does the following: +- The *conanfile.py* together with the contents of the *src* folder have been copied (exported in Conan terms) to the + local Conan cache. +- A new build from source for the ``hello/0.1@demo/testing`` package starts, calling the ``generate()``, ``build()`` and + ``package()`` methods. This creates the binary package in the Conan cache. +- Moves to the *test_package* folder and executes a ``conan install`` + ``conan build`` + ``test()`` method, to check if + the package was correctly created. -- Copies ("export" in Conan terms) the *conanfile.py* from the user folder into the **local cache**. -- Installs the package, forcing it to be built from the sources. -- Moves to the *test_package* folder and creates a temporary *build* folder. -- Executes the :command:`conan install ..`, to install the requirements of the - *test_package/conanfile.py*. Note that it will build "hello" from the sources. -- Builds and launches the *example* consuming application, calling the *test_package/conanfile.py* - ``build()`` and ``test()`` methods respectively. - -Using Conan commands, the :command:`conan create` command would be equivalent to: +We can now validate that the recipe and the package binary are in the cache: .. code-block:: bash - $ conan export . demo/testing - $ conan install hello/0.1@demo/testing --build=hello - # package is created now, use test to test it - $ conan test test_package hello/0.1@demo/testing + $ conan search + Existing package recipes: -The :command:`conan create` command receives the same command line parameters as :command:`conan install` so -you can pass to it the same settings, options, and command line switches. If you want to create and -test packages for different configurations, you could: - -.. code-block:: bash - - $ conan create . demo/testing -s build_type=Debug - $ conan create . demo/testing -o hello:shared=True -s arch=x86 - $ conan create . demo/testing -pr my_gcc49_debug_profile - ... - $ conan create ... + hello/0.1@demo/testing + $ conan search hello/0.1@demo/testing + Existing packages for recipe hello/0.1@demo/testing: -.. _create_omit_user_channel: + Package_ID: 3fb49604f9c2f729b85ba3115852006824e72cab + [options] + shared: False + [settings] + arch: x86_64 + build_type: Release + ... -Omitting user/channel -_____________________ - - -.. warning:: - - This is an **experimental** feature subject to breaking changes in future releases. - -You can create a package omitting the ``user`` and the ``channel``: +The :command:`conan create` command receives the same command line parameters as :command:`conan install` so +you can pass to it the same settings and options. If we execute the following lines, we will create new package +binaries for those configurations: .. code-block:: bash - $ conan create . - - -To reference that package, you have to omit also the ``user`` and the ``channel``. - -Examples -........ - -- Specifying requirements in your recipes: - - .. code-block:: python - :emphasize-lines: 3 - - class HelloTestConan(ConanFile): - settings = "os", "compiler", "build_type", "arch" - requires = "packagename/1.0" - - ... - -- Installing individual packages. The ``conan install`` command we have to use the syntax (always valid) of ``packagename/1.0@`` to disambiguate the - argument that also can be used to specify a path: - - .. code-block:: bash - - $ conan install packagename/1.0@ - - -- Searching for the binary packages of a reference. The ``conan search`` command requires to use the syntax (always valid) of ``packagename/1.0@`` to - disambiguate the usage of a pattern: - - - .. code-block:: bash - - $ conan search packagename/1.0@ - - - Existing packages for recipe packagename/1.0: - - Package_ID: 9bfdcfa2bb925892ecf42e2a018a3f3529826676 - [settings] - arch: x86_64 - build_type: Release - compiler: gcc - compiler.libcxx: libstdc++11 - compiler.version: 7 - os: Linux - Outdated from recipe: False - -- Removing packages: - - .. code-block:: bash - - $ conan remove packagename/1.0 - -- Uploading packages: - - .. code-block:: bash - - $ conan upload packagename/1.0 - - -.. _settings_vs_options: - -Settings vs. Options --------------------- - -We have used settings such as ``os``, ``arch`` and ``compiler``. Note the above package recipe also contains a -``shared`` option (defined as ``options = {"shared": [True, False]}``). What is the difference between -settings and options? - -**Settings** are a project-wide configuration, something that typically affects the whole project that -is being built. For example, the operating system or the architecture would be naturally the same for all -packages in a dependency graph, linking a Linux library for a Windows app, or -mixing architectures is impossible. - -Settings cannot be defaulted in a package recipe. A recipe for a given library cannot say that its default is -``os=Windows``. The ``os`` will be given by the environment in which that recipe is processed. It is -a mandatory input. - -Settings are configurable. You can edit, add, remove settings or subsettings in your *settings.yml* file. -See :ref:`the settings.yml reference `. - -On the other hand, **options** are a package-specific configuration. Static or shared library are not -settings that apply to all packages. Some can be header only libraries while others packages can be just data, -or package executables. Packages can contain a mixture of different artifacts. ``shared`` is a common -option, but packages can define and use any options they want. - -Options are defined in the package recipe, including their supported values, while other can be defaulted by the package -recipe itself. A package for a library can well define that by default it will be a static library (a typical default). -If not specified other. the package will be static. - -There are some exceptions to the above. For example, settings can be defined per-package using the command line: + $ conan create . demo/testing -s build_type=Debug + ... + hello/0.1: Hello World Debug! -.. code-block:: bash + $ conan create . demo/testing -o hello:shared=True + ... + hello/0.1: Hello World Release! - $ conan install . -s mypkg:compiler=gcc -s compiler=clang .. -This will use ``gcc`` for "mypkg" and ``clang`` for the rest of the dependencies (extremely rare case). +These new package binaries will be also stored in the Conan cache, ready to be used by any project in this computer, +we can see them with: -There are situations whereby many packages use the same option, thereby allowing you to set its value once using patterns, like: .. code-block:: bash - $ conan install . -o *:shared=True - -Any doubts? Please check out our :ref:`FAQ section ` or |write_us|. - -.. |write_us| raw:: html - - write us + $ conan search hello/0.1@demo/testing + Existing packages for recipe hello/0.1@demo/testing: + + Package_ID: 127af201a4cdf8111e2e08540525c245c9b3b99e + [options] + shared: True + [settings] + arch: x86_64 + build_type: Release + ... + Package_ID: 3fb49604f9c2f729b85ba3115852006824e72cab + [options] + shared: False + [settings] + arch: x86_64 + build_type: Release + ... + + Package_ID: d057732059ea44a47760900cb5e4855d2bea8714 + [options] + shared: False + [settings] + arch: x86_64 + build_type: Debug + ... + + +Any doubts? Please check out our :ref:`FAQ section ` or open a `Github issue `_ diff --git a/faq/using.rst b/faq/using.rst index fd7256dd7db..87a221a9618 100644 --- a/faq/using.rst +++ b/faq/using.rst @@ -9,11 +9,49 @@ Packaging header-only libraries is similar to other packages. Be sure to start b There are different approaches depending on if you want Conan to run the library unit tests while creating the package or not. Full details are described :ref:`in this how-to guide`. +.. _settings_vs_options: + When to use settings or options? -------------------------------- While creating a package, you may want to add different configurations and variants of the package. There are two main inputs that define -packages: settings and options. Read more about them in :ref:`this section`. +packages: settings and options. + +**Settings** are a project-wide configuration, something that typically affects the whole project that +is being built. For example, the operating system or the architecture would be naturally the same for all +packages in a dependency graph, linking a Linux library for a Windows app, or +mixing architectures is impossible. + +Settings cannot be defaulted in a package recipe. A recipe for a given library cannot say that its default is +``os=Windows``. The ``os`` will be given by the environment in which that recipe is processed. It is +a mandatory input. + +Settings are configurable. You can edit, add, remove settings or subsettings in your *settings.yml* file. +See :ref:`the settings.yml reference `. + +On the other hand, **options** are a package-specific configuration. Static or shared library are not +settings that apply to all packages. Some can be header only libraries while others packages can be just data, +or package executables. Packages can contain a mixture of different artifacts. ``shared`` is a common +option, but packages can define and use any options they want. + +Options are defined in the package recipe, including their supported values, while other can be defaulted by the package +recipe itself. A package for a library can well define that by default it will be a static library (a typical default). +If not specified other. the package will be static. + +There are some exceptions to the above. For example, settings can be defined per-package using the command line: + +.. code-block:: bash + + $ conan install . -s mypkg:compiler=gcc -s compiler=clang .. + +This will use ``gcc`` for "mypkg" and ``clang`` for the rest of the dependencies (extremely rare case). + +There are situations whereby many packages use the same option, thereby allowing you to set its value once using patterns, like: + +.. code-block:: bash + + $ conan install . -o *:shared=True + Can Conan use git repositories as package servers? diff --git a/integrations/ci/jenkins.rst b/integrations/ci/jenkins.rst index c521dae5392..236dc3fb387 100644 --- a/integrations/ci/jenkins.rst +++ b/integrations/ci/jenkins.rst @@ -81,7 +81,7 @@ Create a new Jenkins Pipeline task using this script: Example: Build a Conan package and upload it to Artifactory *********************************************************** -In this example we will call Conan :ref:`test package` command to create a binary packages +In this example we will call Conan ``create`` command to create a binary packages and then upload it to Artifactory. We also upload the `build information`_: diff --git a/reference/conanfile/tools/layout.rst b/reference/conanfile/tools/layout.rst index 7b02d363773..729bdaa6d56 100644 --- a/reference/conanfile/tools/layout.rst +++ b/reference/conanfile/tools/layout.rst @@ -60,7 +60,7 @@ For example, this would implement the standard CMake project layout: def layout(self): cmake_layout(self) -If you want to try it, use the ``conan new hello/0.1 -m v2_cmake`` template. +If you want to try it, use the ``conan new hello/0.1 --template=cmake_lib`` template. It is very important to note that this ``cmake_layout()`` is just calling the ``folders`` and ``cpp`` attributes described before: diff --git a/using_packages/conanfile_txt.rst b/using_packages/conanfile_txt.rst index 1b6b93a8397..007b1665546 100644 --- a/using_packages/conanfile_txt.rst +++ b/using_packages/conanfile_txt.rst @@ -66,7 +66,7 @@ _____________________ This is an **experimental** feature subject to breaking changes in future releases. -If the package was :ref:`created` and :ref:`uploaded` without specifying +If the package was created and uploaded without specifying the ``user`` and ``channel`` you can omit the ``user/channel`` when specifying a reference: