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

gfortran: revive and redesign deprecated recipe #23334

Draft
wants to merge 7 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 10 additions & 13 deletions recipes/gfortran/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,11 @@
sources:
"10.2":
"Windows":
"x86_64":
url: "https://downloads.sourceforge.net/project/mingw-w64/Toolchains%20targetting%20Win64/Personal%20Builds/ray_linn/GCC-10.X-with-ada/GCC-10.2.0-crt-8.0.0-with-ada-20201019.7z"
sha256: "5c3fc254494bc24eb201870f4b781d401cf7279bd03ea1aba6f2ffae771ded44"
"Linux":
"x86_64":
url: "https://gfortran.meteodat.ch/download/x86_64/releases/gcc-10.2.0.tar.xz"
sha256: "5cfaf152db442bb967963ca62d4590980cb2664c5902c1a9578fc8a9c6efe40f"
"Macos":
"x86_64":
url: "https://downloads.sourceforge.net/project/hpc/hpc/g95/gfortran-10.2-bin.tar.gz"
sha256: "2de46f571eefc2b544db4ed6c958c78a5e3e78c4b4b5daab38aabc1b08dd5666"
"13.2.0":
sources:
url:
- "https://mirrors.dotsrc.org/gnu/gcc/gcc-13.2.0/gcc-13.2.0.tar.xz"
- "https://ftpmirror.gnu.org/gnu/gcc/gcc-13.2.0/gcc-13.2.0.tar.xz"
- "https://gcc.gnu.org/ftp/gcc/releases/gcc-13.2.0/gcc-13.2.0.tar.xz"
sha256: "e275e76442a6067341a27f04c5c6b83d8613144004c0413528863dc6b5c743da"
homebrew-patches:
url: "https://raw.githubusercontent.com/Homebrew/formula-patches/3c5cbc8e9cf444a1967786af48e430588e1eb481/gcc/gcc-13.2.0.diff"
sha256: "2df7ef067871a30b2531a2013b3db661ec9e61037341977bfc451e30bf2c1035"
208 changes: 150 additions & 58 deletions recipes/gfortran/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,81 +1,173 @@
import os

from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.files import copy, get, load, save, download
import os
from conan.tools.apple import XCRun, is_apple_os
from conan.tools.env import VirtualBuildEnv, VirtualRunEnv
from conan.tools.files import copy, get, replace_in_file, rmdir, rm, chdir, download, patch
from conan.tools.gnu import Autotools, AutotoolsToolchain
from conan.tools.layout import basic_layout
from conan.tools.microsoft import is_msvc

required_conan_version = ">=1.55.0"

required_conan_version = ">=1.46.0"

class GFortranConan(ConanFile):
name = "gfortran"
description = "The Fortran compiler front end and run-time libraries for GCC"
license = "GPL-3.0-only WITH GCC-exception-3.1"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://gcc.gnu.org/fortran"
topics = ("gnu", "gcc", "fortran", "compiler")
license = "GPL-3.0-or-later"
settings = "os", "arch", "compiler", "build_type"
no_copy_source = True
short_paths = True

deprecated = "gcc"
topics = ("fortran", "gcc", "gnu", "compiler")

# "library" because it also provides libgfortran, libquadmath, etc. in the host context.
# You will usually need to use the package as both a tool_requires() and a requires() in your recipe.
# "shared" to keep things simple and to not accidentally mix static and shared libraries during linking.
package_type = "shared-library"
settings = "os", "compiler", "arch", "build_type"

def configure(self):
self.settings.rm_safe("compiler.libcxx")
self.settings.rm_safe("compiler.cppstd")

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

def layout(self):
basic_layout(self, src_folder="src")

def requirements(self):
self.requires("mpc/1.3.1")
self.requires("mpfr/4.2.0")
self.requires("gmp/6.3.0")
self.requires("zlib/[>=1.2.11 <2]")
self.requires("isl/0.26")

def validate_build(self):
if is_msvc(self):
raise ConanInvalidConfiguration("GCC can't be built with MSVC")

def validate(self):
if self.settings.arch != "x86_64":
raise ConanInvalidConfiguration("No binaries available for the architecture '{}'.".format(self.settings.arch))
if str(self.settings.os) not in ("Windows", "Linux", "Macos"):
raise ConanInvalidConfiguration("No binaries available for the OS '{}'.".format(self.settings.os))
if self.settings.os == "Windows":
raise ConanInvalidConfiguration(
"Windows builds aren't currently supported. Contributions to support this are welcome."
)

def build_requirements(self):
if self.settings.os == "Windows":
self.tool_requires("7zip/22.01")
if self.settings.os == "Linux":
# binutils recipe is broken for Macos, and Windows uses tools
# distributed with msys/mingw
self.tool_requires("binutils/2.42")
self.tool_requires("flex/2.6.4")

def build(self):
if self.settings.os == "Windows":
filename = os.path.join(self.build_folder, "GCC-10.2.0-crt-8.0.0-with-ada-20201019.7z")
download(self, **self.conan_data["sources"][self.version][str(self.settings.os)]["x86_64"], filename=filename)
self.run(f"7z x {filename}")
else:
get(self, **self.conan_data["sources"][self.version][str(self.settings.os)]["x86_64"],
destination=self.build_folder, strip_root=True)
def source(self):
get(self, **self.conan_data["sources"][self.version]["sources"], strip_root=True)
download(self, **self.conan_data["sources"][self.version]["homebrew-patches"], filename="homebrew.patch")

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

runenv = VirtualRunEnv(self)
runenv.generate(scope="build")

tc = AutotoolsToolchain(self)
tc.configure_args.append("--enable-languages=fortran")
tc.configure_args.append("--disable-nls")
tc.configure_args.append("--disable-multilib")
tc.configure_args.append("--disable-bootstrap")
tc.configure_args.append("--disable-fixincludes")
tc.configure_args.append(f"--with-zlib={self.dependencies['zlib'].package_folder}")
tc.configure_args.append(f"--with-isl={self.dependencies['isl'].package_folder}")
tc.configure_args.append(f"--with-gmp={self.dependencies['gmp'].package_folder}")
tc.configure_args.append(f"--with-mpc={self.dependencies['mpc'].package_folder}")
tc.configure_args.append(f"--with-mpfr={self.dependencies['mpfr'].package_folder}")
tc.configure_args.append(f"--with-pkgversion=ConanCenter gfortran {self.version}")
tc.configure_args.append(f"--program-suffix=-{self.version}")
tc.configure_args.append(f"--with-bugurl={self.url}/issues")

@property
def _archive_contents_path(self):
if self.settings.os == "Macos":
return os.path.join(self.build_folder, "local")
elif self.settings.os == "Windows":
return os.path.join(self.build_folder, "mingw64")
else:
return os.path.join(self.build_folder)
xcrun = XCRun(self)
tc.configure_args.append(f"--with-sysroot={xcrun.sdk_path}")
# Set native system header dir to ${{sysroot}}/usr/include to
# isolate installation from the system as much as possible
tc.configure_args.append("--with-native-system-header-dir=/usr/include")
tc.make_args.append("BOOT_LDFLAGS=-Wl,-headerpad_max_install_names")
tc.generate()

@property
def _license_path(self):
return os.path.join(self._archive_contents_path, "share", "info")
# Don't use AutotoolsDeps here - deps are passed directly in configure_args.
# Using AutotoolsDeps causes the compiler tests to fail by erroneously adding
# additional $LIBS to the test compilation

@property
def _library_source_path(self):
return os.path.join(self._archive_contents_path, {
"Linux": "lib64",
"Macos": "lib",
"Windows": os.path.join("lib", "gcc", "x86_64-w64-mingw32", "10.2.0")
}[str(self.settings.os)])

def _extract_license(self):
info = load(self, os.path.join(self._license_path, "gfortran.info"))
license_contents = info[info.find("Version 3"):info.find("END OF TERMS", 1)]
save(self, os.path.join(self.build_folder, "LICENSE"), license_contents)
def build(self):
if is_apple_os(self):
patch(self, patch_file=os.path.join(self.source_folder, "homebrew.patch"), base_path=self.source_folder)

def package_id(self):
del self.info.settings.compiler
del self.info.settings.build_type # The binaries are not specific
# If building on x86_64, change the default directory name for 64-bit libraries to "lib":
replace_in_file(self, os.path.join(self.source_folder, "gcc", "config", "i386", "t-linux64"),
"m64=../lib64", "m64=../lib", strict=False)

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

@property
def _gfortran_full_executable(self):
# e.g. x86_64-pc-linux-gnu
triplet = os.listdir(os.path.join(self.package_folder, "lib", "gcc"))[0]
return f"{triplet}-gfortran-{self.version}"

def package(self):
self._extract_license()
copy(self, "LICENSE", src=self.build_folder, dst=os.path.join(self.package_folder, "licenses"))
copy(self, "gfortran*", src=os.path.join(self._archive_contents_path, "bin"), dst=os.path.join(self.package_folder, "bin"))
copy(self, "libgfortran.a", src=self._library_source_path, dst=os.path.join(self.package_folder, "lib"))
copy(self, "COPYING*", self.source_folder, os.path.join(self.package_folder, "licenses"), keep_path=False)
autotools = Autotools(self)
autotools.install(target="install-strip")
rm(self, "*.la", self.package_folder, recursive=True)
rmdir(self, os.path.join(self.package_folder, "share"))

# Don't export static libraries.
# This only removes libssp_nonshared.a as of v13.2.
rm(self, "*.a", os.path.join(self.package_folder, "lib"))

# Drop ar, nm, ranlib, cpp, etc. to not clash with the existing C/C++ toolchain
for f in self.package_path.joinpath("bin").iterdir():
if f.name != self._gfortran_full_executable:
f.unlink()
with chdir(self, os.path.join(self.package_folder, "bin")):
os.symlink(self._gfortran_full_executable, f"gfortran-{self.version}")
os.symlink(self._gfortran_full_executable, "gfortran")

def package_info(self):
bin_path = os.path.join(self.package_folder, "bin")
self.output.info("Appending PATH environment variable: {}".format(bin_path))
self.cpp_info.includedirs = []
self.env_info.PATH.append(bin_path)
self.cpp_info.libs = ["gfortran"]
# Make sure to always include
# self.requires.expand(["gfortran::libgfortran"])
# in consuming packages to not overlink to all the components listed below.

# libgfortran.so: GNU Fortran Library
self.cpp_info.components["libgfortran"].libs = ["gfortran"]
self.cpp_info.components["libgfortran"].requires = ["libgcc_s"]
# libquadmath.so: GCC Quad Precision Math Library
self.cpp_info.components["libquadmath"].libs = ["quadmath"]
# libgomp.so: GNU Offloading and Multi-Processing Project
self.cpp_info.components["libgomp"].libs = ["gomp"]
# libatomic.so: GNU atomic library
self.cpp_info.components["libatomic"].libs = ["atomic"]
# libgcc_s.so: Dynamic gcc runtime
self.cpp_info.components["libgcc_s"].libs = ["gcc_s"]
# libssp.so: Stack Smashing Protector library
self.cpp_info.components["libssp"].libs = ["ssp"]

self.cpp_info.components["executables"].bindirs = ["bin", "libexec"]
self.cpp_info.components["executables"].requires = [
"mpc::mpc",
"mpfr::mpfr",
"gmp::gmp",
"zlib::zlib",
"isl::isl",
]

gfortran_path = os.path.join(self.package_folder, "bin", self._gfortran_full_executable)
self.buildenv_info.define_path("FC", gfortran_path)

# TODO: Legacy, remove when Conan v1 support is dropped
self.env_info.PATH.append(os.path.join(self.package_folder, "bin"))
self.env_info.FC = gfortran_path
6 changes: 6 additions & 0 deletions recipes/gfortran/all/test_package/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
cmake_minimum_required(VERSION 3.15)
project(test_package LANGUAGES Fortran)

message("CMAKE_Fortran_COMPILER: ${CMAKE_Fortran_COMPILER}")

add_executable(${PROJECT_NAME} test_package.f90)
38 changes: 34 additions & 4 deletions recipes/gfortran/all/test_package/conanfile.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,44 @@
import os

from conan import ConanFile
from conan.tools.build import can_run
from conan.tools.cmake import cmake_layout, CMakeToolchain, CMake
from conan.tools.env import VirtualBuildEnv, VirtualRunEnv


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

def build_requirements(self):
self.tool_requires(self.tested_reference_str)
def requirements(self):
self.requires(self.tested_reference_str)

def layout(self):
cmake_layout(self)

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

# Hack to avoid adding tool_requires(self.tested_reference_str),
# which tends to fail with a missing binaries error
runenv = VirtualRunEnv(self)
runenv.generate(scope="build")
runenv.generate(scope="run")

tc = CMakeToolchain(self)
tc.generate()


def build(self):
if can_run(self):
cmake = CMake(self)
cmake.configure()
cmake.build()

def test(self):
if can_run(self):
self.run("gfortran --version")
self.run("$FC --version", env="conanbuild")
self.run("$FC -dumpversion", env="conanbuild")
bin_path = os.path.join(self.cpp.build.bindir, "test_package")
self.run(bin_path, env="conanrun")
4 changes: 4 additions & 0 deletions recipes/gfortran/all/test_package/test_package.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
2 changes: 1 addition & 1 deletion recipes/gfortran/config.yml
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
versions:
"10.2":
"13.2.0":
folder: all
Loading