Skip to content

Commit

Permalink
Add new layout() test for projects sharing common code in parent fold…
Browse files Browse the repository at this point in the history
…ers (#11556)

* test layout sharing code

* added cmake_layout subfolder

* fix test

* using self.folders.subproject approach

* fix test Linux

* Update conans/model/layout.py

Co-authored-by: Luis Martinez <lasote@gmail.com>

Co-authored-by: Luis Martinez <lasote@gmail.com>
  • Loading branch information
memsharded and lasote committed Jul 12, 2022
1 parent fae0b53 commit 3b84d99
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 11 deletions.
5 changes: 3 additions & 2 deletions conan/tools/cmake/layout.py
Expand Up @@ -14,13 +14,14 @@ def cmake_layout(conanfile, generator=None, src_folder="."):
else:
multi = False

conanfile.folders.source = src_folder
subproject = conanfile.folders.subproject
conanfile.folders.source = src_folder if not subproject else os.path.join(subproject, src_folder)
try:
build_type = str(conanfile.settings.build_type)
except ConanException:
raise ConanException("'build_type' setting not defined, it is necessary for cmake_layout()")

build_folder = "build"
build_folder = "build" if not subproject else os.path.join(subproject, "build")
custom_conf = get_build_folder_custom_vars(conanfile)
if custom_conf:
build_folder = "{}/{}".format(build_folder, custom_conf)
Expand Down
6 changes: 4 additions & 2 deletions conan/tools/layout/__init__.py
Expand Up @@ -6,10 +6,12 @@


def basic_layout(conanfile, src_folder="."):
conanfile.folders.build = "build"
subproject = conanfile.folders.subproject

conanfile.folders.source = src_folder if not subproject else os.path.join(subproject, src_folder)
conanfile.folders.build = "build" if not subproject else os.path.join(subproject, "build")
if conanfile.settings.get_safe("build_type"):
conanfile.folders.build += "-{}".format(str(conanfile.settings.build_type).lower())
conanfile.folders.generators = os.path.join(conanfile.folders.build, "conan")
conanfile.cpp.build.bindirs = ["."]
conanfile.cpp.build.libdirs = ["."]
conanfile.folders.source = src_folder
15 changes: 8 additions & 7 deletions conan/tools/microsoft/layout.py
Expand Up @@ -15,13 +15,14 @@ def vs_layout(conanfile):
if not arch:
raise ConanException("The 'vs_layout' doesn't "
"work with the arch '{}'".format(conanfile.settings.arch))
base = os.path.join(arch, str(conanfile.settings.build_type))
bindirs = os.path.join(arch, str(conanfile.settings.build_type))
else:
base = str(conanfile.settings.build_type)
bindirs = str(conanfile.settings.build_type)

conanfile.folders.build = "."
conanfile.folders.generators = "conan"
conanfile.folders.source = "."
conanfile.cpp.build.libdirs = [base]
conanfile.cpp.build.bindirs = [base]
subproject = conanfile.folders.subproject
conanfile.folders.build = subproject or "."
conanfile.folders.generators = os.path.join(subproject, "conan") if subproject else "conan"
conanfile.folders.source = subproject or "."
conanfile.cpp.build.libdirs = [bindirs]
conanfile.cpp.build.bindirs = [bindirs]
conanfile.cpp.source.includedirs = ["include"]
4 changes: 4 additions & 0 deletions conans/model/layout.py
Expand Up @@ -31,6 +31,10 @@ def __init__(self):
# Relative location of the project root, if the conanfile is not in that project root, but
# in a subfolder: e.g: If the conanfile is in a subfolder then self.root = ".."
self.root = None
# The relative location with respect to the project root of the subproject containing the
# conanfile.py, that makes most of the output folders defined in layouts (cmake_layout, etc)
# start from the subproject again
self.subproject = None

def __repr__(self):
return str(self.__dict__)
Expand Down
114 changes: 114 additions & 0 deletions conans/test/functional/layout/test_in_subfolder.py
@@ -1,5 +1,9 @@
import textwrap

import pytest

from conans.test.assets.cmake import gen_cmakelists
from conans.test.assets.sources import gen_function_cpp
from conans.test.utils.tools import TestClient


Expand Down Expand Up @@ -54,3 +58,113 @@ def build(self):
c.run("build conan")
assert "conanfile.py (pkg/0.1): MYCMAKE-BUILD: mycmake!" in c.out
assert c.load("build/mylib.a") == "mylib"


def test_exports_sources_common_code():
""" very similar to the above, but intended for a multi-package project sharing some
common code
"""
c = TestClient()
conanfile = textwrap.dedent("""
import os
from conan import ConanFile
from conan.tools.files import load, copy, save
class Pkg(ConanFile):
name = "pkg"
version = "0.1"
def layout(self):
self.folders.root = ".."
self.folders.source = "pkg"
self.folders.build = "build"
def export_sources(self):
source_folder = os.path.join(self.recipe_folder, "..")
copy(self, "*.txt", source_folder, self.export_sources_folder)
copy(self, "*.cmake", source_folder, self.export_sources_folder)
def source(self):
cmake = load(self, "CMakeLists.txt")
self.output.info("MYCMAKE-SRC: {}".format(cmake))
def build(self):
path = os.path.join(self.source_folder, "CMakeLists.txt")
cmake = load(self, path)
self.output.info("MYCMAKE-BUILD: {}".format(cmake))
path = os.path.join(self.export_sources_folder, "common", "myutils.cmake")
cmake = load(self, path)
self.output.info("MYUTILS-BUILD: {}".format(cmake))
""")
c.save({"pkg/conanfile.py": conanfile,
"pkg/CMakeLists.txt": "mycmake!",
"common/myutils.cmake": "myutils!"})
c.run("create pkg")
assert "pkg/0.1: MYCMAKE-SRC: mycmake!" in c.out
assert "pkg/0.1: MYCMAKE-BUILD: mycmake!" in c.out
assert "pkg/0.1: MYUTILS-BUILD: myutils!" in c.out

# Local flow
c.run("install pkg")
# SOURCE NOT CALLED! It doesnt make sense (will fail due to local exports)
c.run("build pkg")
assert "conanfile.py (pkg/0.1): MYCMAKE-BUILD: mycmake!" in c.out
assert "conanfile.py (pkg/0.1): MYUTILS-BUILD: myutils!" in c.out


@pytest.mark.tool_cmake
def test_exports_sources_common_code_layout():
""" Equal to the previous test, but actually building and using cmake_layout
"""
c = TestClient()
conanfile = textwrap.dedent("""
import os
from conan import ConanFile
from conan.tools.cmake import cmake_layout, CMake
from conan.tools.files import load, copy, save
class Pkg(ConanFile):
name = "pkg"
version = "0.1"
settings = "os", "compiler", "build_type", "arch"
generators = "CMakeToolchain"
def layout(self):
self.folders.root = ".."
self.folders.subproject = "pkg"
cmake_layout(self)
def export_sources(self):
source_folder = os.path.join(self.recipe_folder, "..")
copy(self, "*", source_folder, self.export_sources_folder)
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
self.run(os.path.join(self.cpp.build.bindirs[0], "myapp"))
""")
cmake_include = "include(${CMAKE_CURRENT_LIST_DIR}/../common/myutils.cmake)"
c.save({"pkg/conanfile.py": conanfile,
"pkg/app.cpp": gen_function_cpp(name="main", includes=["../common/myheader"],
preprocessor=["MYDEFINE"]),
"pkg/CMakeLists.txt": gen_cmakelists(appsources=["app.cpp"],
custom_content=cmake_include),
"common/myutils.cmake": 'message(STATUS "MYUTILS.CMAKE!")',
"common/myheader.h": '#define MYDEFINE "MYDEFINEVALUE"'})
c.run("create pkg")
assert "MYUTILS.CMAKE!" in c.out
assert "main: Release!" in c.out
assert "MYDEFINE: MYDEFINEVALUE" in c.out

# Local flow
c.run("install pkg")
c.run("build pkg")
assert "MYUTILS.CMAKE!" in c.out
assert "main: Release!" in c.out
assert "MYDEFINE: MYDEFINEVALUE" in c.out

c.run("install pkg -s build_type=Debug")
c.run("build pkg")
assert "MYUTILS.CMAKE!" in c.out
assert "main: Debug!" in c.out
assert "MYDEFINE: MYDEFINEVALUE" in c.out
Empty file.
25 changes: 25 additions & 0 deletions conans/test/integration/toolchains/gnu/test_basic_layout.py
@@ -0,0 +1,25 @@
import os
import platform
import textwrap

from conans.test.utils.tools import TestClient


def test_basic_layout_subproject():
c = TestClient()
conanfile = textwrap.dedent("""
from conan import ConanFile
from conan.tools.layout import basic_layout
class Pkg(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "AutotoolsToolchain"
def layout(self):
self.folders.root = ".."
self.folders.subproject = "pkg"
basic_layout(self)
""")
c.save({"pkg/conanfile.py": conanfile})
c.run("install pkg")
ext = "sh" if platform.system() != "Windows" else "bat"
assert os.path.isfile(os.path.join(c.current_folder, "pkg", "build-release", "conan",
"conanautotoolstoolchain.{}".format(ext)))
22 changes: 22 additions & 0 deletions conans/test/integration/toolchains/microsoft/test_vs_layout.py
@@ -0,0 +1,22 @@
import os
import textwrap

from conans.test.utils.tools import TestClient


def test_vs_layout_subproject():
c = TestClient()
conanfile = textwrap.dedent("""
from conan import ConanFile
from conan.tools.microsoft import vs_layout
class Pkg(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "MSBuildToolchain"
def layout(self):
self.folders.root = ".."
self.folders.subproject = "pkg"
vs_layout(self)
""")
c.save({"pkg/conanfile.py": conanfile})
c.run("install pkg")
assert os.path.isfile(os.path.join(c.current_folder, "pkg", "conan", "conantoolchain.props"))

0 comments on commit 3b84d99

Please sign in to comment.