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

Include compiler version in build hash #1430

Closed
wants to merge 3 commits into from
Closed
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
9 changes: 9 additions & 0 deletions src/alire/alire-builds-hashes.adb
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,15 @@ package body Alire.Builds.Hashes is
-- Configuration variables
-- TBD

-- Compiler version. Changing compiler will result in incompatible
-- ALI files and produce rebuilds, so it must be part of the hash.
-- Incidentally, this serves to separate by cross-target too.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compiler is able to detect incompatible build artifact, but it's probably better to avoid the error message.

Also note that this will not handle all case for cross-target since a given cross compiler can support multiple instruction sets. For instance arm-elf can do Arm Cortex-M0, Cortex-M7, etc.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also note that this will not handle all case for cross-target since a given cross compiler can support multiple instruction sets. For instance arm-elf can do Arm Cortex-M0, Cortex-M7, etc.

Right; for those I understood that we're not going to do anything directly, but that the project file will separate the objects into folders?

I guess at some point we can use libgpr to extract the necessary info from the project file?

declare
Compiler : constant Releases.Release := Root.Compiler;
begin
Add ("version", Compiler.Name.As_String, Compiler.Version.Image);
end;

-- Dependencies recursive hash? Since a crate can use a dependency
-- config spec, it is possible in the worst case for a crate to
-- require unique builds that include their dependencies hash
Expand Down
10 changes: 8 additions & 2 deletions src/alire/alire-roots.adb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ with Ada.Unchecked_Deallocation;

with Alire.Builds;
with Alire.Conditional;
with Alire.Config;
with Alire.Dependencies.Containers;
with Alire.Directories;
with Alire.Environment;
Expand All @@ -16,7 +15,7 @@ with Alire.Properties.Actions.Executor;
with Alire.Roots.Optional;
with Alire.Solutions.Diffs;
with Alire.Spawn;
with Alire.Toolchains;
with Alire.Toolchains.Solutions;
with Alire.User_Pins.Maps;
with Alire.Utils.TTY;
with Alire.Utils.User_Input;
Expand Down Expand Up @@ -251,6 +250,13 @@ package body Alire.Roots is
return This.Build_Hasher.Hash (Name);
end Build_Hash;

--------------
-- Compiler --
--------------

function Compiler (This : in out Root) return Releases.Release
is (Toolchains.Solutions.Compiler (This.Solution));

-------------
-- Install --
-------------
Expand Down
5 changes: 5 additions & 0 deletions src/alire/alire-roots.ads
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ package Alire.Roots is
function Build_Context (This : in out Root)
return Alire.Environment.Context;

function Compiler (This : in out Root) return Releases.Release;
-- Return the compiler that would be used to compile this solution,
-- either because of an explicit dependency or with the actual toolchain
-- configuration.

procedure Export_Build_Environment (This : in out Root);
-- Export the build environment (PATH, GPR_PROJECT_PATH) of the given root

Expand Down
61 changes: 58 additions & 3 deletions src/alire/alire-toolchains-solutions.adb
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,17 @@ with AAA.Strings;

with Alire.Index;
with Alire.Root;
with Alire.Solver;

package body Alire.Toolchains.Solutions is

-------------------
-- Add_Toolchain --
-------------------

function Add_Toolchain (Solution : Alire.Solutions.Solution)
return Alire.Solutions.Solution
function Add_Toolchain (Solution : Alire.Solutions.Solution;
Deploy : Boolean := True)
return Alire.Solutions.Solution
is

------------------------
Expand Down Expand Up @@ -46,7 +48,7 @@ package body Alire.Toolchains.Solutions is

-- This shouldn't happen normally, but it can happen if the user
-- has just changed the cache location.
if not Tool_Is_External (Tool) then
if Deploy and then not Tool_Is_External (Tool) then
Redeploy_If_Needed (Tool_Milestone (Tool));
end if;

Expand All @@ -67,6 +69,59 @@ package body Alire.Toolchains.Solutions is
return Result;
end Add_Toolchain;

--------------
-- Compiler --
--------------

function Compiler (Solution : Alire.Solutions.Solution)
return Releases.Release
is

--------------------------
-- Environment_Compiler --
--------------------------

function Environment_Compiler return Releases.Release is
begin
Index.Detect_Externals (GNAT_Crate, Root.Platform_Properties);
return Solver.Find (GNAT_External_Crate,
Policy => Solver.Default_Options.Age);
exception
when Query_Unsuccessful =>
Raise_Checked_Error
(Errors.New_Wrapper
.Wrap ("Unable to determine compiler version.")
.Wrap ("Check that the workspace solution is complete "
& "and a compiler is available.")
.Get);
end Environment_Compiler;

begin
if not Solution.Depends_On (GNAT_Crate) then
declare
With_GNAT : constant Alire.Solutions.Solution :=
Add_Toolchain (Solution,
Deploy => False);
begin
if not With_GNAT.Depends_On (GNAT_Crate) then
-- This means that no compiler (or None) has been selected
-- with `alr toolchain`, so we return whichever one is in
-- the environment.
return Environment_Compiler;
else
return Compiler (With_GNAT);
end if;
end;
end if;

-- At this point we have a GNAT in the solution

Assert (Solution.Releases_Providing (GNAT_Crate).Length in 1,
"Solution contains more than one compiler?");

return Solution.Releases_Providing (GNAT_Crate).First_Element;
end Compiler;

---------------------
-- Is_In_Toolchain --
---------------------
Expand Down
11 changes: 9 additions & 2 deletions src/alire/alire-toolchains-solutions.ads
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,19 @@ package Alire.Toolchains.Solutions is

-- Needed to break circularity

function Add_Toolchain (Solution : Alire.Solutions.Solution)
function Add_Toolchain (Solution : Alire.Solutions.Solution;
Deploy : Boolean := True)
return Alire.Solutions.Solution;
-- If no release in the solution is a compiler/builder, add the configured
-- ones (if defined) to the solution. This is used just before launching
-- the build, so the configured tools are used despite not being in a
-- regular solution.
-- regular solution. If Deploy, the toolchain will be readied if not
-- already available.

function Compiler (Solution : Alire.Solutions.Solution)
return Releases.Release;
-- Retrieve the compiler that will be used by this solution, be it because
-- it contains already one, or else checking the selected toolchain.

function Is_In_Toolchain (Release : Releases.Release) return Boolean;
-- Say if this Release is part of the user-configured toolchain
Expand Down
21 changes: 15 additions & 6 deletions testsuite/drivers/alr.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,13 @@

import os
import os.path

import re
from shutil import copytree
from e3.os.process import Run, quote_arg

from e3.fs import mkdir
from e3.os.process import Run, quote_arg
from e3.testsuite.driver.classic import ProcessResult

import re


TESTSUITE_ROOT = os.path.dirname(os.path.dirname(
os.path.abspath(__file__)))

Expand Down Expand Up @@ -530,4 +528,15 @@ def alr_builds_dir() -> str:
"""
Return the path to the builds directory
"""
return os.path.join(alr_config_dir(), "cache", "builds")
return os.path.join(alr_config_dir(), "cache", "builds")


def external_compiler_version() -> str:
"""
Return the version of the external compiler
"""
# Obtain available compilers
p = run_alr("toolchain")

# Capture version
return re.search("gnat_external ([0-9.]+)", p.out, re.MULTILINE).group(1)
8 changes: 8 additions & 0 deletions testsuite/drivers/builds.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,17 @@

from glob import glob
import os
from shutil import rmtree
from drivers.alr import alr_builds_dir


def clear_builds_dir() -> None:
"""
Clear the shared build directory
"""
rmtree(path())


def find_dir(crate_name: str) -> str:
"""
Find the build dir of a crate in the shared build directory
Expand Down
2 changes: 1 addition & 1 deletion testsuite/drivers/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,4 +272,4 @@ def __exit__(self, exc_type, exc_val, exc_tb):
# Release the file lock
import fcntl
fcntl.flock(self.lock_file.fileno(), fcntl.LOCK_UN)
self.lock_file.close()
self.lock_file.close()
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
description = "GNAT is a compiler for the Ada programming language"
name = "gnat_external"

maintainers = ["[email protected]"]
maintainers-logins = ["mosteo"]

[[external]]
kind = "version-output"
# We look for make instead that should be always installed.
version-command = ["make", "--version"]
version-regexp = ".*Make ([\\d\\.]+).*"
provides = "gnat"
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
description = "Fake GNAT native crate"
name = "gnat_native"
version = "7777.0.0"
maintainers = ["[email protected]"]
maintainers-logins = ["mylogin"]
provides = ["gnat=7777.0"]

# Test dynamic expression, but for all OSes
[origin."case(os)"."..."]
url = "file:../../../crates/libhello_1.0.0.tgz"
hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"]
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
description = "Fake GNAT native crate"
name = "gnat_native"
version = "8888.0.0"
maintainers = ["[email protected]"]
maintainers-logins = ["mylogin"]
provides = ["gnat=8888.0"]

# Although the compiler is fake, we use this path in some tests
environment.'case(os)'.'windows'.TEST_PATH.append = '${CRATE_ROOT}\bin'
environment.'case(os)'.'...'.TEST_PATH.append = '${CRATE_ROOT}/bin'

# Test dynamic expression, but for all OSes
[origin."case(os)"."..."]
url = "file:../../../crates/libhello_1.0.0.tgz"
hashes = ["sha512:99fa3a55540d0655c87605b54af732f76a8a363015f183b06e98aa91e54c0e69397872718c5c16f436dd6de0fba506dc50c66d34a0e5c61fb63cb01fa22f35ac"]
16 changes: 16 additions & 0 deletions testsuite/fixtures/build_hash_index/he/hello/hello-1.0.0.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
description = "\"Hello, world!\" demonstration project"
long-description = "This is an example of long description in a multi-line string.\n\nMarkdown formating `can` be used to have \"nice\" display on the website.\n"
name = "hello"
version = "1.0.0"
website = "example.com"
authors = ["Bob", "Alice"]
licenses = "GPL-3.0-only OR MIT"
maintainers = ["[email protected]", "[email protected]"]
maintainers-logins = ["mylogin"]
tags = ["tag1", "other-tag"]

[[depends-on]]
libhello = "^1.0"

[origin]
url = "file:../../../crates/hello_1.0.0"
29 changes: 29 additions & 0 deletions testsuite/fixtures/build_hash_index/he/hello/hello-1.0.1.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
description = "\"Hello, world!\" demonstration project"
long-description = "This is an example of long description in a multi-line string.\n\nMarkdown formating `can` be used to have \"nice\" display on the website.\n"
name = "hello"
version = "1.0.1"
website = "example.com"
authors = ["Bob", "Alice"]
licenses = "GPL-3.0-only OR MIT"
maintainers = ["[email protected]", "[email protected]"]
maintainers-logins = ["mylogin"]
tags = ["tag1", "other-tag"]

[[depends-on]]
libhello = "^1.0"

[configuration.variables]
Var1={type="Boolean"}
Var2={type="String", default="str"}
Var3={type="Enum", values=["A", "B"], default="A"}
Var4={type="Integer", default=0}
Var5={type="Integer", first=-1, last=1, default=0}
Var7={type="Real", default=0.0}
Var6={type="Real", first=-1.0, last=1.0, default=0.0}

[configuration.values]
hello.Var1=true # So far it is possible for a crate to set its own var
libhello.Var1=false

[origin]
url = "file:../../../crates/hello_1.0.1"
1 change: 1 addition & 0 deletions testsuite/fixtures/build_hash_index/index.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
version = "1.1"
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
description = "\"Hello, world!\" demonstration project support library"
name = "libhello"
version = "1.0.0"
maintainers = ["[email protected]"]
maintainers-logins = ["mylogin"]
tags = ["libhello-tag1"]

[configuration.variables]
Var1={type="Boolean", default=true}

[gpr-externals]
TEST_GPR_EXTERNAL = ["gpr_ext_A", "gpr_ext_B", "gpr_ext_C"]
TEST_FREEFORM_UNSET = "" # to test build hashing with an unset var

[gpr-set-externals]
TEST_GPR_EXTERNAL = "gpr_ext_B"
TEST_UNDECLARED = "used_by_another_crate"

[environment]
TEST_ENV.set = "myenv"

[origin]
url = "file:../../../crates/libhello_1.0.0"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
description = "Utility for directing compilation"
name = "make"
maintainers = ["[email protected]"]
maintainers-logins = ["mylogin"]

[[external]]
kind = "system"
origin = [] # Empty on purpose to ensure unavailable in tests
Loading
Loading