Skip to content

Commit

Permalink
Versioned Clang automatic configuration (#1)
Browse files Browse the repository at this point in the history
* Versioned Clang automatic configuration

Currently, without annoying `toolset.using` directives in `user-config.jam`, `b2 toolset=clang-xx` silently uses clang++ binary, even if it is a different version than requested. Instead of copycating GCC or reinventing a wheel I have generalized GCC automatic configuration and used it for Clang.
  • Loading branch information
Kojoley authored Apr 23, 2021
1 parent aabf877 commit 9552adf
Show file tree
Hide file tree
Showing 7 changed files with 226 additions and 108 deletions.
1 change: 0 additions & 1 deletion .cirrus.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ freebsd_task:
- { name: 'FreeBSD, Clang 9', env: { TOOLSET: clang, TEST_TOOLSET: clang, CXX: 'clang++90', PACKAGE: 'llvm90' }, freebsd_instance: { image_family: 'freebsd-12-2' } }
- { name: 'FreeBSD, Clang 8', env: { TOOLSET: clang, TEST_TOOLSET: clang, CXX: 'clang++80', PACKAGE: 'llvm80' }, freebsd_instance: { image_family: 'freebsd-12-2' } }
- { name: 'FreeBSD, Clang 7', env: { TOOLSET: clang, TEST_TOOLSET: clang, CXX: 'clang++70', PACKAGE: 'llvm70' }, freebsd_instance: { image_family: 'freebsd-12-2' } }
- { name: 'FreeBSD, Clang 6', env: { TOOLSET: clang, TEST_TOOLSET: clang, CXX: 'clang++60', PACKAGE: 'llvm60' }, freebsd_instance: { image_family: 'freebsd-12-2' } }
# To install with ports we need to initialize the package manager. To avoid
# confirmation prompts we need to set an env var.
install_script: [
Expand Down
59 changes: 59 additions & 0 deletions src/build/version.jam
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Copyright 2021 Nikita Kniazev
# Copyright 2002, 2003, 2004, 2006 Vladimir Prus
# Copyright 2008, 2012 Jurko Gospodnetic
# Distributed under the Boost Software License, Version 1.0.
Expand Down Expand Up @@ -99,6 +100,34 @@ rule version-less ( lhs + : rhs + )
return $(result) ;
}

# Returns "true" if the required version is compatible with the having one.
# This uses sematic versioning where (major.x.y) is compatible with
# (major.n.m) and (major.x.z). And is incompatible for other values.
#
rule version-compatible ( req + : has + )
{
numbers.check $(req) ;
numbers.check $(has) ;

if $(req) = $(has)
{
return true ;
}

while $(req) && [ numbers.equal $(req[1]) $(has[1]:E=0) ]
{
req = $(req[2-]) ;
has = $(has[2-]) ;
}

if $(req)
{
return ;
}

return true ;
}


# Returns "true" if the current JAM version version is at least the given
# version.
Expand Down Expand Up @@ -163,4 +192,34 @@ rule __test__ ( )
assert.false version-less 03 1 10 0 : 3 1 10 0 0 ;

# TODO: Add tests for invalid input data being sent to version-less.


assert.true version-compatible 4 : 4 ;
assert.true version-compatible 4 : 4 9 ;
assert.false version-compatible 4 9 : 4 ;
assert.true version-compatible 4 9 : 4 9 ;
assert.false version-compatible 4 9 1 : 4 9 ;
assert.true version-compatible 4 9 1 : 4 9 1 ;
assert.false version-compatible 4 8 : 4 9 ;
assert.false version-compatible 4 8 1 : 4 9 ;
assert.false version-compatible 4 8 1 : 4 9 1 ;
assert.true version-compatible 5 : 5 ;
assert.false version-compatible 5 : 4 ;
assert.false version-compatible 5 : 4 9 ;
assert.false version-compatible 5 1 : 5 ;
assert.true version-compatible 5 1 : 5 1 ;
assert.false version-compatible 5 1 : 5 2 ;
assert.false version-compatible 5 1 1 : 5 ;
assert.false version-compatible 5 1 1 : 5 1 ;
assert.false version-compatible 5 2 : 5 ;
assert.false version-compatible 5 2 : 5 1 ;
assert.true version-compatible 5 2 : 5 2 ;
assert.true version-compatible 4 : 4 0 ;
assert.true version-compatible 4 0 : 4 ;
assert.true version-compatible 04 : 4 ;
assert.true version-compatible 04 : 04 ;
assert.true version-compatible 04 : 4 ;
assert.true version-compatible 04 00 : 04 ;
assert.true version-compatible 04 : 04 00 ;
}

28 changes: 18 additions & 10 deletions src/tools/clang-darwin.jam
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright Vladimir Prus 2004.
# Copyright Noel Belcourt 2007.
# Copyright Nikita Kniazev 2020.
# Copyright Nikita Kniazev 2020-2021.
# Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE.txt
# or copy at https://www.bfgroup.xyz/b2/LICENSE.txt)
Expand Down Expand Up @@ -54,15 +54,11 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ]
# compile and link options allow you to specify addition command line options for each version
rule init ( version ? : command * : options * )
{
command = [ common.get-invocation-command clang-darwin : clang++
: $(command) : /usr/bin /usr/local/bin ] ;

# Determine the version
local command-string = $(command:J=" ") ;
if $(command)
{
version ?= [ MATCH "version ([0-9]+[.][0-9]+)"
: [ SHELL "$(command-string) --version" ] ] ;
command = [ common.find-compiler clang-darwin : clang++ : $(version) : $(command)
: /usr/bin /usr/local/bin ] ;
local command-string = [ common.make-command-string $(command) ] ;
if ! $(version) { # ?= operator does not short-circuit
version ?= [ get-short-version $(command-string) ] ;
}

local condition = [ common.check-init-parameters clang
Expand All @@ -80,6 +76,18 @@ rule init ( version ? : command * : options * )
toolset.flags clang-darwin.archive .AR $(condition) : $(archiver[1]) ;
}

rule get-full-version ( command-string )
{
import clang-linux ;
return [ clang-linux.get-full-version $(command-string) ] ;
}

rule get-short-version ( command-string )
{
import clang-linux ;
return [ clang-linux.get-short-version $(command-string) ] ;
}

SPACE = " " ;

toolset.flags clang-darwin.compile.m OPTIONS <mflags> ;
Expand Down
24 changes: 15 additions & 9 deletions src/tools/clang-linux.jam
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
# Copyright 2021 Nikita Kniazev
# Copyright 2020 Rene Rivera
# Copyright (c) 2003 Michael Stevens
# Copyright (c) 2010-2011 Bryce Lelbach (blelbach@cct.lsu.edu, maintainer)
Expand Down Expand Up @@ -51,15 +52,10 @@ if [ MATCH (--debug-configuration) : [ modules.peek : ARGV ] ] {
}

rule init ( version ? : command * : options * ) {
command = [ common.get-invocation-command clang-linux : clang++
: $(command) ] ;

# Determine the version
if $(command) {
local command-string = \"$(command)\" ;
command-string = $(command-string:J=" ") ;
version ?= [ MATCH "version ([0-9.]+)"
: [ SHELL "$(command-string) --version" ] ] ;
command = [ common.find-compiler clang-linux : clang++ : $(version) : $(command) ] ;
local command-string = [ common.make-command-string $(command) ] ;
if ! $(version) { # ?= operator does not short-circuit
version ?= [ get-short-version $(command-string) ] ;
}

local condition = [ common.check-init-parameters clang-linux
Expand Down Expand Up @@ -110,6 +106,16 @@ rule init ( version ? : command * : options * ) {
toolset.flags clang-linux.archive .AR $(condition) : $(archiver[1]) ;
}

rule get-full-version ( command-string )
{
return [ gcc.get-full-version $(command-string) ] ;
}

rule get-short-version ( command-string )
{
return [ gcc.get-short-version $(command-string) : 4 ] ;
}

###############################################################################
# Flags

Expand Down
73 changes: 73 additions & 0 deletions src/tools/common.jam
Original file line number Diff line number Diff line change
Expand Up @@ -1082,6 +1082,79 @@ local rule arch-and-model-tag ( name : type ? : property-set )
return $(arch)$(address-model) ;
}

# TODO: probably needs to escape '"' in command parts
# TODO: if part does not contain whitespaces it does not require escaping
rule make-command-string ( command + )
{
local command-string = \"$(command)\" ;
return $(command-string:J=" ") ;
}

rule find-compiler ( toolset : tool : version ? : command * : additional-paths * )
{
#1): use user-provided command
if $(command)
{
if ! [ get-invocation-command-nodefault $(toolset) : $(tool)
: $(command) : $(additional-paths) ]
{
local command-string = [ make-command-string $(command) ] ;
errors.error toolset $(toolset) "initialization:"
: provided command '$(command-string)' not found
: initialized from [ errors.nearest-user-location ] ;
}
}
#2): enforce user-provided version
else if $(version)
{
command = [ get-invocation-command-nodefault $(toolset) : $(tool)-$(version)
: : $(additional-paths) ] ;

#2.1) fallback: check whether "$(tool)" reports the requested version
if ! $(command) { # ?= operator does not short-circuit
command ?= [ get-invocation-command-nodefault $(toolset) : $(tool)
: : $(additional-paths) ] ;
}

if ! $(command)
{
errors.error toolset $(toolset) "initialization:"
: version '$(version)' requested but neither
'$(tool)-$(version)' nor default '$(tool)' found
: initialized from [ errors.nearest-user-location ] ;
}

import $(toolset) ;
local tool-version = [ $(toolset).get-full-version $(command) ] ;

import version ;
if ! [ version.version-compatible [ SPLIT_BY_CHARACTERS $(version) : . ]
: [ SPLIT_BY_CHARACTERS $(tool-version) : . ] ]
{
errors.error toolset $(toolset) "initialization:"
: version '$(version)' requested but
'$(tool)-$(version)' not found and version
'$(tool-version:J=.)' of default '$(command)'
does not match
: initialized from [ errors.nearest-user-location ]
;
}
}
#3) default: no command and no version specified, try using "$(tool)"
else
{
command = [ get-invocation-command-nodefault $(toolset) : $(tool)
: : $(additional-paths) ] ;
if ! $(command)
{
errors.error toolset $(toolset) "initialization:"
: no command provided, default command '$(tool)' not found
: initialized from [ errors.nearest-user-location ] ;
}
}
return $(command) ;
}

rule __test__ ( )
{
import assert ;
Expand Down
Loading

0 comments on commit 9552adf

Please sign in to comment.