Skip to content

Commit

Permalink
[gcc] Migrate to conan v2, add fortran
Browse files Browse the repository at this point in the history
* Migrate gcc recipe to conan v2
* Add fortran as an enabled language to ensure that gfortran is built
* Add binutils as a build_requires to remove dependency on system
  binaries
* Refactor package test to ensure that the package compilers are under
  test and not the system compilers
* Add fortran test binary
* Export environment variables in the buildenv for gcc, g++, gfortran,
  ar, nm, ranlib
  • Loading branch information
samuel-emrys committed Oct 31, 2022
1 parent 8eabe5f commit 2218a5b
Show file tree
Hide file tree
Showing 10 changed files with 262 additions and 125 deletions.
6 changes: 3 additions & 3 deletions recipes/gcc/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
sources:
"10.2.0":
sha256: 27e879dccc639cd7b0cc08ed575c1669492579529b53c9ff27b0b96265fa867d
url: https://ftp.gnu.org/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.gz
"12.2.0":
sha256: ac6b317eb4d25444d87cf29c0d141dedc1323a1833ec9995211b13e1a851261c
url: https://ftp.gnu.org/gnu/gcc/gcc-12.2.0/gcc-12.2.0.tar.gz
"10.2.0":
sha256: 27e879dccc639cd7b0cc08ed575c1669492579529b53c9ff27b0b96265fa867d
url: https://ftp.gnu.org/gnu/gcc/gcc-10.2.0/gcc-10.2.0.tar.gz
222 changes: 129 additions & 93 deletions recipes/gcc/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,126 +1,162 @@
from conans import ConanFile, tools, AutoToolsBuildEnvironment
from conans.errors import ConanException, ConanInvalidConfiguration
from conan import ConanFile
from conan.tools.gnu import Autotools, AutotoolsToolchain, AutotoolsDeps
from conan.errors import ConanInvalidConfiguration
from conan.tools.layout import basic_layout
from conan.tools.apple import XCRun
from conan.tools.files import copy, get, replace_in_file, rmdir, rm
from conan.tools.build import cross_building
from conan.tools.env import VirtualBuildEnv
import os

required_conan_version = ">=1.29.1"
required_conan_version = ">=1.53.0"


class GccConan(ConanFile):
name = "gcc"
description = "The GNU Compiler Collection includes front ends for C, " \
"C++, Objective-C, Fortran, Ada, Go, and D, as well as " \
"libraries for these languages (libstdc++,...). "
description = (
"The GNU Compiler Collection includes front ends for C, "
"C++, Objective-C, Fortran, Ada, Go, and D, as well as "
"libraries for these languages (libstdc++,...). "
)
topics = ("gcc", "gnu", "compiler", "c", "c++")
homepage = "https://gcc.gnu.org"
url = "https://github.com/conan-io/conan-center-index"
license = "GPL-3.0-only"
settings = "os", "compiler", "arch", "build_type"
_autotools = None

def build_requirements(self):
self.build_requires("flex/2.6.4")

def _configure_autotools(self):
if self._autotools:
return self._autotools
self._autotools = AutoToolsBuildEnvironment(self)
pkgversion = 'conan GCC %s' % self.version
bugurl = self.url + '/issues'
libdir = "%s/lib/gcc/%s" % (self.package_folder, self.version)
args = [
"--enable-languages=c,c++",
"--disable-nls",
"--disable-multilib",
"--disable-bootstrap",
"--with-system-zlib",
"--with-gmp=%s" % self.deps_cpp_info['gmp'].rootpath,
'--with-mpc=%s' % self.deps_cpp_info["mpc"].rootpath,
"--with-mpfr=%s" % self.deps_cpp_info["mpfr"].rootpath,
"--without-isl",
"--libdir=%s" % libdir,
'--with-pkgversion=%s' % pkgversion,
"--program-suffix=-%s" % self.version,
"--with-bugurl=%s" % bugurl
]
if self.settings.os == "Macos":
xcrun = tools.XCRun(self.settings)
args.extend([
'--with-native-system-header-dir=/usr/include',
"--with-sysroot={}".format(xcrun.sdk_path)
])
self._autotools.libs = [] # otherwise causes config.log to fail finding -lmpc
def configure(self):
if self.settings.compiler in ["clang", "apple-clang"]:
# xgcc: error: unrecognized command-line option -stdlib=libc++
if self.settings.compiler.libcxx == "libc++":
self._autotools.cxx_flags.remove("-stdlib=libc++")
elif self.settings.compiler.libcxx in ["libstdc++", "libstdc++11"]:
self._autotools.cxx_flags.remove("-stdlib=libstdc++")
self._autotools.configure(args=args, configure_dir=self._source_subfolder)
return self._autotools

@property
def _source_subfolder(self):
return "source_subfolder"
# Can't remove this from cxxflags with autotools - so get rid of it
del self.settings.compiler.libcxx

def build_requirements(self):
self.tool_requires("binutils/2.38")
self.tool_requires("flex/2.6.4")

def requirements(self):
self.requires("mpc/1.2.0")
self.requires("mpfr/4.1.0")
self.requires("gmp/6.2.0")
self.requires("zlib/1.2.11")
self.requires("gmp/6.2.1")
self.requires("zlib/1.2.12")
self.requires("isl/0.24")

def configure(self):
if self.settings.os == "Windows":
raise ConanInvalidConfiguration("Windows builds aren't supported (yet), sorry")
if tools.cross_building(self.settings):
def package_id(self):
del self.info.settings.compiler

def validate(self):
if self.info.settings.os == "Windows":
raise ConanInvalidConfiguration(
"Windows builds aren't supported (yet), sorry"
)
if cross_building(self):
raise ConanInvalidConfiguration("no cross-building support (yet), sorry")

def source(self):
tools.get(**self.conan_data["sources"][self.version])
extracted_dir = "gcc-%s" % self.version
os.rename(extracted_dir, self._source_subfolder)
def layout(self):
basic_layout(self, src_folder="source")

def generate(self):
# Ensure binutils and flex are on the path
buildenv = VirtualBuildEnv(self)
buildenv.generate()

tc = AutotoolsToolchain(self)
tc.configure_args.append("--enable-languages=c,c++,fortran")
tc.configure_args.append("--disable-nls")
tc.configure_args.append("--disable-multilib")
tc.configure_args.append("--disable-bootstrap")
tc.configure_args.append("--with-system-zlib")
tc.configure_args.append(f"--prefix={self.package_folder}")
tc.configure_args.append(f"--with-isl={self.deps_cpp_info['isl'].rootpath}")
tc.configure_args.append(f"--with-gmp={self.deps_cpp_info['gmp'].rootpath}")
tc.configure_args.append(f"--with-mpc={self.deps_cpp_info['mpc'].rootpath}")
tc.configure_args.append(f"--with-mpfr={self.deps_cpp_info['mpfr'].rootpath}")
tc.configure_args.append(f"--with-pkgversion=conan GCC {self.version}")
tc.configure_args.append(f"--program-suffix=-{self.version}")
tc.configure_args.append(f"--with-bugurl={self.url}/issues")

if self.info.settings.os == "Macos":
xcrun = XCRun(self.settings)
tc.configure_args.append("--with-native-system-header-dir=/usr/include")
tc.configure_args.append(f"--with-sysroot={xcrun.sdk_path}")
tc.make_args.append("BOOT_LDFLAGS=-Wl")
tc.make_args.append("-headerpad_max_install_names")
tc.generate()

deps = AutotoolsDeps(self)
deps.generate()

@property
def _make_args(self):
if self.settings.os == "Macos":
return ["BOOT_LDFLAGS=-Wl,-headerpad_max_install_names"]
return []
def source(self):
get(self, **self.conan_data["sources"][self.version], strip_root=True)

def build(self):
# If building on x86_64, change the default directory name for 64-bit libraries to "lib":
libdir = "%s/lib/gcc/%s" % (self.package_folder, self.version)
tools.replace_in_file(os.path.join(self.source_folder,
self._source_subfolder, "gcc", "config", "i386", "t-linux64"),
"m64=../lib64", "m64=../lib", strict=False)
replace_in_file(
self,
os.path.join(self.source_folder, "gcc", "config", "i386", "t-linux64"),
"m64=../lib64",
"m64=../lib",
strict=False,
)

# Ensure correct install names when linking against libgcc_s;
# see discussion in https://github.com/Homebrew/legacy-homebrew/pull/34303
tools.replace_in_file(os.path.join(self.source_folder,
self._source_subfolder, "libgcc", "config", "t-slibgcc-darwin"),
"@shlib_slibdir@", libdir, strict=False)
autotools = self._configure_autotools()
autotools.make(args=self._make_args)

def package_id(self):
del self.info.settings.compiler
replace_in_file(
self,
os.path.join(self.source_folder, "libgcc", "config", "t-slibgcc-darwin"),
"@shlib_slibdir@",
os.path.join(self.package_folder, "lib"),
strict=False,
)

autotools = Autotools(self)
autotools.configure()
autotools.make()

def package(self):
autotools = self._configure_autotools()
if self.settings.build_type == "Debug":
autotools.install(args=self._make_args)
else:
autotools.make(args=["install-strip"] + self._make_args)
tools.rmdir(os.path.join(self.package_folder, "share"))
tools.remove_files_by_mask(self.package_folder, "*.la")
self.copy(pattern="COPYING*", dst="licenses", src=self._source_subfolder)
autotools = Autotools(self)
autotools.make(target="install-strip")

rmdir(self, os.path.join(self.package_folder, "share"))
rm(self, "*.la", self.package_folder, recursive=True)
copy(
self,
pattern="COPYING*",
dst=os.path.join(self.package_folder, "licenses"),
src=self.source_folder,
keep_path=False,
)

def package_info(self):
if self.info.settings.os in ["Linux", "FreeBSD"]:
self.cpp_info.system_libs.append("m")
self.cpp_info.system_libs.append("rt")
self.cpp_info.system_libs.append("pthread")
self.cpp_info.system_libs.append("dl")

bindir = os.path.join(self.package_folder, "bin")
self.output.info("Appending PATH env var with : " + bindir)
self.env_info.PATH.append(bindir)
self.output.info("Prepending PATH env var with: " + bindir)
self.buildenv_info.prepend_path("PATH", bindir)

cc = os.path.join(bindir, f"gcc-{self.version}")
self.output.info("Creating CC env var with: " + cc)
self.buildenv_info.define("CC", cc)

cxx = os.path.join(bindir, f"g++-{self.version}")
self.output.info("Creating CXX env var with: " + cxx)
self.buildenv_info.define("CXX", cxx)

fc = os.path.join(bindir, f"gfortran-{self.version}")
self.output.info("Creating FC env var with: " + fc)
self.buildenv_info.define("FC", fc)

ar = os.path.join(bindir, f"gcc-ar-{self.version}")
self.output.info("Creating AR env var with: " + ar)
self.buildenv_info.define("AR", ar)

cc = os.path.join(bindir, "gcc-%s" % self.version)
self.output.info("Creating CC env var with : " + cc)
self.env_info.CC = cc
nm = os.path.join(bindir, f"gcc-nm-{self.version}")
self.output.info("Creating NM env var with: " + nm)
self.buildenv_info.define("NM", nm)

cxx = os.path.join(bindir, "g++-%s" % self.version)
self.output.info("Creating CXX env var with : " + cxx)
self.env_info.CXX = cxx
ranlib = os.path.join(bindir, f"gcc-ranlib-{self.version}")
self.output.info("Creating RANLIB env var with: " + ranlib)
self.buildenv_info.define("RANLIB", ranlib)
97 changes: 72 additions & 25 deletions recipes/gcc/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,34 +1,81 @@
from conans import ConanFile, tools
import os
import shutil
from conan import ConanFile
from conan.tools.build import cross_building
from conan.tools.env import VirtualBuildEnv, VirtualRunEnv


class TestPackageConan(ConanFile):
class GccTestConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake"

@property
def file_io(self):
return {
"c": {
"compiler": "$CC",
"src": os.path.join(self.source_folder, "hello.c"),
"bin": os.path.join(self.build_folder, "hello_c"),
},
"cpp": {
"compiler": "$CXX",
"src": os.path.join(self.source_folder, "hello.cpp"),
"bin": os.path.join(self.build_folder, "hello_cpp"),
},
"fortran": {
"compiler": "$FC",
"src": os.path.join(self.source_folder, "hello.f90"),
"bin": os.path.join(self.build_folder, "hello_f90"),
},
}

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

runenv = VirtualRunEnv(self)
runenv.generate()

def build(self):
self.run("echo PATH: $PATH")
for language, files in self.file_io.items():
self.output.info(f"Testing build using {language} compiler")
# Confirm compiler is propagated to env
envvar = files["compiler"].split("$")[1]
self.run(f"echo {envvar}: {files['compiler']}", env="conanbuild")
self.run(f"{files['compiler']} --version", env="conanbuild")
self.run(f"{files['compiler']} -dumpversion", env="conanbuild")

# Confirm files can be compiled
self.run(
f"{files['compiler']} {files['src']} -o {files['bin']}",
env="conanbuild",
)
self.output.info(f"Successfully built {files['bin']}")

def test(self):
def chmod_plus_x(name):
if os.name == 'posix':
if os.name == "posix":
os.chmod(name, os.stat(name).st_mode | 0o111)

cc = self.deps_env_info["gcc"].CC
cxx = self.deps_env_info["gcc"].CXX
hello_c = os.path.join(self.source_folder, "hello.c")
hello_cpp = os.path.join(self.source_folder, "hello.cpp")
self.run("%s --version" % cc, run_environment=True)
self.run("%s --version" % cxx, run_environment=True)
self.run("%s -dumpversion" % cc, run_environment=True)
self.run("%s -dumpversion" % cxx, run_environment=True)
self.run("%s %s -o hello_c" % (cc, hello_c), run_environment=True)
self.run("%s %s -o hello_cpp" % (cxx, hello_cpp), run_environment=True)
if not tools.cross_building(self.settings):
chmod_plus_x("hello_c")
chmod_plus_x("hello_cpp")
self.run("./hello_c", run_environment=True)
self.run("./hello_cpp", run_environment=True)
if tools.which("readelf"):
self.run("readelf -l hello_c", run_environment=True)
self.run("readelf -l hello_cpp", run_environment=True)
if tools.which("otool"):
self.run("otool -L hello_c", run_environment=True)
self.run("otool -L hello_cpp", run_environment=True)
for language, files in self.file_io.items():
self.output.info(f"Testing application built using {language} compiler")
if not cross_building(self):
chmod_plus_x(f"{files['bin']}")

if self.settings.os == "Linux":
if shutil.which("readelf"):
self.run(f"readelf -l {files['bin']}", env="conanrun")
else:
self.output.info(
"readelf is not on the PATH. Skipping readelf test."
)

if self.settings.os == "Macos":
if shutil.which("otool"):
self.run(f"otool -L {files['bin']}", env="conanrun")
else:
self.output.info(
"otool is not on the PATH. Skipping otool test."
)

self.run(f"{files['bin']}", env="conanrun")
2 changes: 1 addition & 1 deletion recipes/gcc/all/test_package/hello.c
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

int main()
{
puts("Hello, World!\n");
puts(" gcc: Hello, World!");
return 0;
}

2 changes: 1 addition & 1 deletion recipes/gcc/all/test_package/hello.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

int main()
{
std::cout << "Hello, World!\n";
std::cout << " g++: Hello, World!\n";
return 0;
}

4 changes: 4 additions & 0 deletions recipes/gcc/all/test_package/hello.f90
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
program hello
implicit none
write(*,*) 'gfortran: Hello, World!'
end program hello
Loading

0 comments on commit 2218a5b

Please sign in to comment.