Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move layout to build #2364

Merged
merged 13 commits into from
Feb 2, 2022
5 changes: 2 additions & 3 deletions creating_packages/getting_started.rst
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Using the :command:`conan new` command will create a "Hello World" C++ library e

The generated files are:

- **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.
- **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.
- **CMakeLists.txt**: A simple generic *CMakeLists.txt*, with nothing specific about Conan in it.
- **src** folder: the *src* folder that contains the simple C++ "hello" library.
- (optional) **test_package** folder: contains an *example* application that will require and link with the created package.
Expand All @@ -47,8 +47,7 @@ Let's have a look at the package recipe *conanfile.py*:
.. code-block:: python

from conans import ConanFile
from conan.tools.cmake import CMakeToolchain, CMake
from conan.tools.layout import cmake_layout
from conan.tools.cmake import CMakeToolchain, CMake, cmake_layout

class HelloConan(ConanFile):
name = "hello"
Expand Down
6 changes: 5 additions & 1 deletion reference/conanfile/tools/cmake.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,14 @@ conan.tools.cmake

These tools are **experimental** and subject to breaking changes.

You can use ``conan new hello/0.1 --template=cmake_lib`` and ``conan new hello/0.1 --template=cmake_exe`` templates
to try this CMake integration.


.. toctree::
:maxdepth: 2

cmake/cmakedeps
cmake/cmaketoolchain
cmake/cmake
cmake/cmake
cmake/cmake_layout
73 changes: 73 additions & 0 deletions reference/conanfile/tools/cmake/cmake_layout.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
.. _cmake_layout:

cmake_layout
------------

.. warning::

These tools are **experimental** and subject to breaking changes.


For example, this would implement the standard CMake project layout:

.. code:: python

from conan.tools.cmake import cmake_layout

def layout(self):
cmake_layout(self)


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 in the (:ref:`layout reference <conan_tools_layout>`):


.. code:: python

def cmake_layout(conanfile, generator=None):
gen = conanfile.conf["tools.cmake.cmaketoolchain:generator"] or generator
if gen:
multi = "Visual" in gen or "Xcode" in gen or "Multi-Config" in gen
elif conanfile.settings.compiler == "Visual Studio" or conanfile.settings.compiler == "msvc":
multi = True
else:
multi = False

conanfile.folders.source = "."
if multi:
conanfile.folders.build = "build"
conanfile.folders.generators = "build/conan"
else:
build_type = str(conanfile.settings.build_type).lower()
conanfile.folders.build = "cmake-build-{}".format(build_type)
conanfile.folders.generators = os.path.join(conanfile.folders.build, "conan")

conanfile.cpp.local.includedirs = ["src"]
if multi:
_dir = os.path.join(conanfile.folders.build, str(conanfile.settings.build_type))
conanfile.cpp.local.libdirs = [_dir]
conanfile.cpp.local.bindirs = [_dir]
else:
conanfile.cpp.local.libdirs = [conanfile.folders.build]
conanfile.cpp.local.bindirs = [conanfile.folders.build]
franramirez688 marked this conversation as resolved.
Show resolved Hide resolved


First, it is important to notice that the layout depends on the CMake generator that will be used.
So if defined from ``[conf]``, that value will be used. If defined in recipe, then the recipe should
pass it as ``cmake_layout(self, cmake_generator)``.

The definitions of the folders is different if it is a multi-config generator (like Visual Studio or Xcode),
or a single-config generator (like Unix Makefiles). In the first case, the folder is the same irrespective
of the build type, and the build system will manage the different build types inside that folder. But
single-config generators like Unix Makefiles, must use a different folder for each different configuration
(as a different build_type Release/Debug).

Finally, the location where the libraries are created also depends. For multi-config, the respective libraries
will be located in a dedicated folder inside the build folder, while for single-config, the libraries will
be located directly in the build folder.

This helper defines a few things, for example that the source folder is called ``"."``, meaning that Conan will
expect the sources in the same directory were the conanfile is (most likely the project root).
This could be customized without fully changing the layout:
18 changes: 2 additions & 16 deletions reference/conanfile/tools/cmake/cmaketoolchain.rst
Original file line number Diff line number Diff line change
Expand Up @@ -147,26 +147,12 @@ The booleans assigned to a variable will be translated to ``ON`` and ``OFF`` sym
Will generate the sentences: ``set(FOO ON ...)`` and ``set(VAR OFF ...)``.


find_builddirs
++++++++++++++

Defaulted to ``True``. If ``True`` Conan adds the ``cpp_info.builddirs`` from the requirements to the
``CMAKE_PREFIX_PATH`` and ``CMAKE_MODULE_PATH`` variables. That would allow finding the config files or modules
packaged in the dependencies and also including them from the consumer CMakeLists.txt.

.. code:: python

def generate(self):
tc = CMakeToolchain(self)
tc.find_builddirs = False
tc.generate()


Generators
++++++++++

The ``CMakeToolchain`` is intended to run with the ``CMakeDeps`` dependencies generator. It might temporarily
work with others like ``cmake_find_package`` and ``cmake_find_package_multi``, but this will be removed soon.
The ``CMakeToolchain`` is intended to run with the ``CMakeDeps`` dependencies generator. Please do not use other
CMake legacy generators (like ``cmake``, or ``cmake_paths``) with it.


Using a custom toolchain file
Expand Down
70 changes: 8 additions & 62 deletions reference/conanfile/tools/layout.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,78 +15,24 @@ conan.tools.layout
Predefined layouts
------------------

There are some pre-defined common layouts, ready to be simply used in recipes.
There are some pre-defined common layouts, ready to be simply used in recipes:

For example, this would implement the standard CMake project layout:
- ``cmake_layout()``: :ref:`a layout for a typical CMake project <cmake_layout>`
- ``meson_layout()``: :ref:`a layout for a typical Meson project <meson_layout>`
- ``vs_layout()``: a layout for a typical Visual Studio project

.. code:: python

from conan.tools.layout import cmake_layout

def layout(self):
cmake_layout(self)

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:


.. code:: python

def cmake_layout(conanfile, generator=None):
gen = conanfile.conf["tools.cmake.cmaketoolchain:generator"] or generator
if gen:
multi = "Visual" in gen or "Xcode" in gen or "Multi-Config" in gen
elif conanfile.settings.compiler == "Visual Studio" or conanfile.settings.compiler == "msvc":
multi = True
else:
multi = False

conanfile.folders.source = "."
if multi:
conanfile.folders.build = "build"
conanfile.folders.generators = "build/conan"
else:
build_type = str(conanfile.settings.build_type).lower()
conanfile.folders.build = "cmake-build-{}".format(build_type)
conanfile.folders.generators = os.path.join(conanfile.folders.build, "conan")

conanfile.cpp.local.includedirs = ["src"]
if multi:
_dir = os.path.join(conanfile.folders.build, str(conanfile.settings.build_type))
conanfile.cpp.local.libdirs = [_dir]
conanfile.cpp.local.bindirs = [_dir]
else:
conanfile.cpp.local.libdirs = [conanfile.folders.build]
conanfile.cpp.local.bindirs = [conanfile.folders.build]

First, it is important to notice that the layout depends on the CMake generator that will be used.
So if defined from ``[conf]``, that value will be used. If defined in recipe, then the recipe should
pass it as ``cmake_layout(self, cmake_generator)``.

The definitions of the folders is different if it is a multi-config generator (like Visual Studio or Xcode),
or a single-config generator (like Unix Makefiles). In the first case, the folder is the same irrespective
of the build type, and the build system will manage the different build types inside that folder. But
single-config generators like Unix Makefiles, must use a different folder for each different configuration
(as a different build_type Release/Debug).

Finally, the location where the libraries are created also depends. For multi-config, the respective libraries
will be located in a dedicated folder inside the build folder, while for single-config, the libraries will
be located directly in the build folder.

This helper defines a few things, for example that the source folder is called ``"."``, meaning that Conan will
expect the sources in the same directory were the conanfile is (most likely the project root).
The predefined layouts define a few things, for example in the ``cmake_layout()`` the source folder is called ``"."``, meaning that Conan will
expect the sources in the same directory were the conanfile is (most likely the project root, where a ``CMakeLists.txt`` file will be typically found).
memsharded marked this conversation as resolved.
Show resolved Hide resolved
This could be customized without fully changing the layout:


.. code:: python

def layout(self):
cmake_layout(self)
self.folders.source = "mysrcfolder"


Even if this pre-defined layout doesn't suit your specific projects layout, it is a good example how you could
implement your own logic (and probably put it in a common ``python_require`` if you are going to use it in multiple
Even if this pre-defined layout doesn't suit your specific projects layout, checking how they implement their logic
memsharded marked this conversation as resolved.
Show resolved Hide resolved
whows how you could implement your own logic (and probably put it in a common ``python_require`` if you are going to use it in multiple
memsharded marked this conversation as resolved.
Show resolved Hide resolved
packages).