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

gn: migrate to Conan v2 #18847

Merged
merged 14 commits into from
May 6, 2024
191 changes: 108 additions & 83 deletions recipes/gn/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,128 +1,153 @@
from conans import ConanFile, tools
from conans.errors import ConanInvalidConfiguration
from contextlib import contextmanager
import conan.tools.files as tools_files
import conan.tools.scm as tools_scm
import os
import shutil
import sys
import textwrap
import time

Check warning on line 5 in recipes/gn/all/conanfile.py

View workflow job for this annotation

GitHub Actions / Lint changed conanfile.py (v2 migration)

Unused import time

required_conan_version = ">=1.46.0"
from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.apple import is_apple_os, XCRun
from conan.tools.build import check_min_cppstd
from conan.tools.env import VirtualBuildEnv, Environment
from conan.tools.files import chdir, copy, get, load, save, replace_in_file
from conan.tools.layout import basic_layout
from conan.tools.microsoft import is_msvc, VCVars
from conan.tools.scm import Version

required_conan_version = ">=1.47.0"


class GnConan(ConanFile):
name = "gn"
description = "GN is a meta-build system that generates build files for Ninja."
url = "https://github.com/conan-io/conan-center-index"
topics = ("gn", "build", "system", "ninja")
license = "BSD-3-Clause"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://gn.googlesource.com/"
topics = ("build system", "ninja")

package_type = "application"
settings = "os", "arch", "compiler", "build_type"

@property
def _source_subfolder(self):
return "source_subfolder"
def layout(self):
basic_layout(self, src_folder="src")

def package_id(self):
del self.info.settings.compiler

@property
def _minimum_compiler_version_supporting_cxx17(self):
return {
"Visual Studio": 15,
"msvc": 191,
"gcc": 7,
"clang": 4,
"apple-clang": 10,
}.get(str(self.settings.compiler))

def validate(self):
if self.settings.compiler.cppstd:
tools.check_min_cppstd(self, 17)
check_min_cppstd(self, 17)
else:
if self._minimum_compiler_version_supporting_cxx17:
if tools_scm.Version(self.settings.compiler.version) < self._minimum_compiler_version_supporting_cxx17:
if Version(self.settings.compiler.version) < self._minimum_compiler_version_supporting_cxx17:
raise ConanInvalidConfiguration("gn requires a compiler supporting c++17")
else:
self.output.warn("gn recipe does not recognize the compiler. gn requires a compiler supporting c++17. Assuming it does.")

def package_id(self):
del self.info.settings.compiler

def source(self):
tools_files.get(self, **self.conan_data["sources"][self.version], destination=self._source_subfolder)
self.output.warning(
"gn recipe does not recognize the compiler. gn requires a compiler supporting c++17."
" Assuming it does."
)

def build_requirements(self):
# FIXME: add cpython build requirements for `build/gen.py`.
self.build_requires("ninja/1.10.2")
self.build_requires("ninja/1.11.1")

@contextmanager
def _build_context(self):
if self.settings.compiler == "Visual Studio":
with tools.vcvars(self.settings):
yield
else:
compiler_defaults = {}
if self.settings.compiler == "gcc":
compiler_defaults = {
"CC": "gcc",
"CXX": "g++",
"AR": "ar",
"LD": "g++",
}
elif self.settings.compiler == "clang":
compiler_defaults = {
"CC": "clang",
"CXX": "clang++",
"AR": "ar",
"LD": "clang++",
}
env = {}
for k in ("CC", "CXX", "AR", "LD"):
v = tools.get_env(k, compiler_defaults.get(k, None))
if v:
env[k] = v
with tools.environment_append(env):
yield

@staticmethod
def _to_gn_platform(os_, compiler):
if tools.is_apple_os(os_):
def source(self):
get(self, **self.conan_data["sources"][self.version])

@property
def _gn_platform(self):
if is_apple_os(self):
return "darwin"
if compiler == "Visual Studio":
if is_msvc(self):
return "msvc"
# Assume gn knows about the os
return str(os_).lower()
return str(self.settings.os).lower()

@property
def _cxx(self):
compilers_by_conf = self.conf.get("tools.build:compiler_executables", default={}, check_type=dict)
cxx = compilers_by_conf.get("cpp") or VirtualBuildEnv(self).vars().get("CXX")
if cxx:
return cxx
if self.settings.compiler == "apple-clang":
return XCRun(self).cxx
compiler_version = self.settings.compiler.version
major = Version(compiler_version).major
if self.settings.compiler == "gcc":
return shutil.which(f"g++-{compiler_version}") or shutil.which(f"g++-{major}") or shutil.which("g++") or ""
if self.settings.compiler == "clang":
return shutil.which(f"clang++-{compiler_version}") or shutil.which(f"clang++-{major}") or shutil.which("clang++") or ""
return ""

def generate(self):
env = VirtualBuildEnv(self)
env.generate()

# Make sure CXX env var is set, otherwise gn defaults it to clang++
# https://gn.googlesource.com/gn/+/refs/heads/main/build/gen.py#386
env = Environment()
env.define("CXX", self._cxx)
env.vars(self).save_script("conanbuild_gn")

if is_msvc(self):
vcvars = VCVars(self)
vcvars.generate()

configure_args = [
"--no-last-commit-position",
f"--host={self._gn_platform}",
]
if self.settings.build_type in ["Debug", "RelWithDebInfo"]:
configure_args.append("-d")
save(self, os.path.join(self.source_folder, "configure_args"), " ".join(configure_args))

def build(self):
with tools.chdir(self._source_subfolder):
with self._build_context():
# Generate dummy header to be able to run `build/ben.py` with `--no-last-commit-position`. This allows running the script without the tree having to be a git checkout.
tools.save(os.path.join("src", "gn", "last_commit_position.h"),
textwrap.dedent("""\
#pragma once
#define LAST_COMMIT_POSITION "1"
#define LAST_COMMIT_POSITION_NUM 1
"""))
conf_args = [
"--no-last-commit-position",
"--host={}".format(self._to_gn_platform(self.settings.os, self.settings.compiler)),
]
if self.settings.build_type == "Debug":
conf_args.append("-d")
self.run("{} build/gen.py {}".format(sys.executable, " ".join(conf_args)), run_environment=True)
# Try sleeping one second to avoid time skew of the generated ninja.build file (and having to re-run build/gen.py)
time.sleep(1)
build_args = [
"-C", "out",
"-j{}".format(tools.cpu_count()),
]
self.run("ninja {}".format(" ".join(build_args)), run_environment=True)
with chdir(self, self.source_folder):
# Generate dummy header to be able to run `build/gen.py` with `--no-last-commit-position`.
# This allows running the script without the tree having to be a git checkout.
save(self, os.path.join(self.source_folder, "src", "gn", "last_commit_position.h"),
textwrap.dedent("""\
#pragma once
#define LAST_COMMIT_POSITION "1"
#define LAST_COMMIT_POSITION_NUM 1
"""),
)

# Disable GenerateLastCommitPosition()
replace_in_file(self, os.path.join(self.source_folder, "build/gen.py"),
"def GenerateLastCommitPosition(host, header):",
"def GenerateLastCommitPosition(host, header):\n return")

self.run(f"{sys.executable} build/gen.py " + load(self, "configure_args"))
self.run(f"ninja -C out -j{os.cpu_count()} -v")

def package(self):
self.copy("LICENSE", src=self._source_subfolder, dst="licenses")
self.copy("gn", src=os.path.join(self._source_subfolder, "out"), dst="bin")
self.copy("gn.exe", src=os.path.join(self._source_subfolder, "out"), dst="bin")
copy(self, "LICENSE", src=self.source_folder, dst=os.path.join(self.package_folder, "licenses"))
if self.settings.os == "Windows":
copy(self, "gn.exe",
src=os.path.join(self.source_folder, "out"),
dst=os.path.join(self.package_folder, "bin"))
else:
copy(self, "gn",
src=os.path.join(self.source_folder, "out"),
dst=os.path.join(self.package_folder, "bin"))

def package_info(self):
self.cpp_info.includedirs = []
self.cpp_info.frameworkdirs = []
self.cpp_info.libdirs = []
self.cpp_info.resdirs = []

bin_path = os.path.join(self.package_folder, "bin")
self.output.info("Appending PATH environment variable: {}".format(bin_path))
self.output.info(f"Appending PATH environment variable: {bin_path}")
self.env_info.PATH.append(bin_path)
self.cpp_info.includedirs = []
75 changes: 31 additions & 44 deletions recipes/gn/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,46 +1,28 @@
from conans import ConanFile, CMake, tools
from contextlib import contextmanager
import os

from conan import ConanFile
from conan.tools.apple import is_apple_os
from conan.tools.build import can_run, cross_building
from conan.tools.env import VirtualRunEnv, VirtualBuildEnv
from conan.tools.layout import basic_layout
from conan.tools.microsoft import unix_path


class TestPackageConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
settings = "os", "arch", "compiler", "build_type"
generators = "VCVars"
test_type = "explicit"

def build_requirements(self):
self.build_requires("ninja/1.10.2")
self.tool_requires(self.tested_reference_str)
self.tool_requires("ninja/1.11.1")

@contextmanager
def _build_context(self):
if self.settings.compiler == "Visual Studio":
with tools.vcvars(self.settings):
yield
else:
compiler_defaults = {}
if self.settings.compiler == "gcc":
compiler_defaults = {
"CC": "gcc",
"CXX": "g++",
"AR": "ar",
"LD": "g++",
}
elif self.settings.compiler in ("apple-clang", "clang"):
compiler_defaults = {
"CC": "clang",
"CXX": "clang++",
"AR": "ar",
"LD": "clang++",
}
env = {}
for k in ("CC", "CXX", "AR", "LD"):
v = tools.get_env(k, compiler_defaults.get(k, None))
if v:
env[k] = v
with tools.environment_append(env):
yield
def layout(self):
basic_layout(self)

@property
def _target_os(self):
if tools.is_apple_os(self.settings.os):
if is_apple_os(self):
return "mac"
# Assume gn knows about the os
return {
Expand All @@ -53,17 +35,22 @@ def _target_cpu(self):
"x86_64": "x64",
}.get(str(self.settings.arch), str(self.settings.arch))

def generate(self):
VirtualBuildEnv(self).generate()
VirtualRunEnv(self).generate(scope="run")
VirtualRunEnv(self).generate(scope="build")

def build(self):
if not tools.cross_building(self.settings):
with tools.chdir(self.source_folder):
gn_args = [
os.path.relpath(os.path.join(self.build_folder, "bin"), os.getcwd()).replace("\\", "/"),
"--args=\"target_os=\\\"{os_}\\\" target_cpu=\\\"{cpu}\\\"\"".format(os_=self._target_os, cpu=self._target_cpu),
]
self.run("gn gen {}".format(" ".join(gn_args)), run_environment=True)
with self._build_context():
self.run("ninja -v -j{} -C bin".format(tools.cpu_count()), run_environment=True)
if not cross_building(self):
rel_bindir = unix_path(self, os.path.relpath(os.path.join(self.cpp.build.bindir), os.getcwd()))
gn_args = [
rel_bindir,
f'--args="target_os=\\"{self._target_os}\\" target_cpu=\\"{self._target_cpu}\\""',
]
self.run("gn gen " + " ".join(gn_args))
self.run(f"ninja -v -j{os.cpu_count()} -C {rel_bindir}")

def test(self):
if not tools.cross_building(self.settings):
self.run(os.path.join("bin", "test_package"), run_environment=True)
if can_run(self):
bin_path = os.path.join(self.cpp.build.bindir, "test_package")
self.run(bin_path, env="conanrun")
2 changes: 1 addition & 1 deletion recipes/gn/all/test_package/test_package.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#include <iostream>

int main(int argc, char* argv[]) {
int main() {
std::cout << get_test_shared_text() << "\n";
std::cout << get_test_static_text() << "\n";
return 0;
Expand Down
Loading