From d44e8290b2924812a71a89e290a4b568b42c1735 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Fri, 7 Aug 2026 13:18:00 +0200 Subject: [PATCH 1/6] Improve target-os detection Signed-off-by: Uilian Ries --- src/tools/clang-linux.jam | 27 +++++++++++++++++++++++++++ src/tools/gcc.jam | 15 ++++++++++----- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/src/tools/clang-linux.jam b/src/tools/clang-linux.jam index 03f5546c29..5e64bc288a 100644 --- a/src/tools/clang-linux.jam +++ b/src/tools/clang-linux.jam @@ -38,6 +38,7 @@ import numbers ; import os ; import property ; import rc ; +import regex ; import set ; feature.extend-subfeature toolset clang : platform : linux ; @@ -74,6 +75,32 @@ rule init ( version ? : command * : options * ) { : version $(version) ] ; common.handle-options clang-linux : $(condition) : $(command) : $(options) ; + + # Autodetect target-os from the compiler's own triple, + # unless the toolset was already told what to target. + if $(command) && ! [ feature.get-values : $(options) ] + { + local machine = [ MATCH "^([^ ]+)" : + [ SHELL "$(command-string) -dumpmachine" ] ] ; + local target-os ; + switch $(machine:L) + { + case *android* : target-os ?= android ; + case *mingw* : target-os ?= windows ; + case *cygwin* : target-os ?= cygwin ; + case *linux* : target-os ?= linux ; + case *darwin* : target-os ?= darwin ; + case *freebsd* : target-os ?= freebsd ; + case *solaris* : target-os ?= solaris ; + case *qnx* : target-os ?= qnxnto ; + } + if $(target-os) + { + local conditionx = [ regex.replace $(condition) "/" "," ] ; + toolset.add-defaults $(conditionx)\:$(target-os) ; + } + } + clang.init-flags clang-linux : $(condition) : $(version) : [ feature.get-values : $(options) ] ; diff --git a/src/tools/gcc.jam b/src/tools/gcc.jam index af25131bd4..4aebeff3fc 100644 --- a/src/tools/gcc.jam +++ b/src/tools/gcc.jam @@ -199,11 +199,16 @@ rule init ( version ? : command * : options * : requirement * ) } switch $(machine:L) { - case *mingw* : target-os ?= windows ; - case *cygwin* : target-os ?= cygwin ; - case *linux* : target-os ?= linux ; - case *aix* : target-os ?= aix ; - case *hpux* : target-os ?= hpux ; + case *mingw* : target-os ?= windows ; + case *cygwin* : target-os ?= cygwin ; + case *android* : target-os ?= android ; + case *linux* : target-os ?= linux ; + case *aix* : target-os ?= aix ; + case *hpux* : target-os ?= hpux ; + case *darwin* : target-os ?= darwin ; + case *freebsd* : target-os ?= freebsd ; + case *solaris* : target-os ?= solaris ; + case *qnx* : target-os ?= qnxnto ; # TODO: finish this list. } } From be4547cefbc656c6a6c84e6888186b40c72cac2e Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Fri, 7 Aug 2026 14:54:55 +0200 Subject: [PATCH 2/6] Autodetect target-os for darwin-clang Signed-off-by: Uilian Ries --- src/tools/clang-darwin.jam | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/tools/clang-darwin.jam b/src/tools/clang-darwin.jam index 07ef394769..6aaccb4824 100644 --- a/src/tools/clang-darwin.jam +++ b/src/tools/clang-darwin.jam @@ -14,6 +14,7 @@ import toolset : flags ; import common ; import errors ; import generators ; +import regex ; feature.extend-subfeature toolset clang : platform : darwin ; # FIXME: import order affects default value for 'platform' subfeature @@ -50,6 +51,35 @@ rule init ( version ? : command * : options * ) : version $(version) ] ; common.handle-options clang-darwin : $(condition) : $(command) : $(options) ; + + # Autodetect target-os from the compiler's own triple, unless the + # toolset was already told what to target. Without this, a + # per-target NDK wrapper (e.g. aarch64-linux-android21-clang++) + # would silently inherit the darwin host default below, and + # clang.init-flags' hardcoded darwin condition would then + # inject a conflicting --target=arm64-apple-darwin over whatever the + # wrapper set for itself. + if $(command) && ! [ feature.get-values : $(options) ] + { + local machine = [ MATCH "^([^ ]+)" : + [ SHELL "$(command-string) -dumpmachine" ] ] ; + local target-os ; + switch $(machine:L) + { + case *android* : target-os ?= android ; + case *linux* : target-os ?= linux ; + case *darwin* : target-os ?= darwin ; + case *freebsd* : target-os ?= freebsd ; + case *solaris* : target-os ?= solaris ; + case *qnx* : target-os ?= qnxnto ; + } + if $(target-os) + { + local conditionx = [ regex.replace $(condition) "/" "," ] ; + toolset.add-defaults $(conditionx)\:$(target-os) ; + } + } + clang.init-flags clang-darwin : $(condition) : $(version) : [ feature.get-values : $(options) ] ; From 96feafedbb4804cc41e9d6ff39d23f5351e68625 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Fri, 7 Aug 2026 15:02:04 +0200 Subject: [PATCH 3/6] Centralize clang logic for target-os Signed-off-by: Uilian Ries --- src/tools/clang-darwin.jam | 28 ++-------------------------- src/tools/clang-linux.jam | 25 ++----------------------- src/tools/clang.jam | 28 ++++++++++++++++++++++++++++ 3 files changed, 32 insertions(+), 49 deletions(-) diff --git a/src/tools/clang-darwin.jam b/src/tools/clang-darwin.jam index 6aaccb4824..2745ff7fc8 100644 --- a/src/tools/clang-darwin.jam +++ b/src/tools/clang-darwin.jam @@ -14,7 +14,6 @@ import toolset : flags ; import common ; import errors ; import generators ; -import regex ; feature.extend-subfeature toolset clang : platform : darwin ; # FIXME: import order affects default value for 'platform' subfeature @@ -52,32 +51,9 @@ rule init ( version ? : command * : options * ) common.handle-options clang-darwin : $(condition) : $(command) : $(options) ; - # Autodetect target-os from the compiler's own triple, unless the - # toolset was already told what to target. Without this, a - # per-target NDK wrapper (e.g. aarch64-linux-android21-clang++) - # would silently inherit the darwin host default below, and - # clang.init-flags' hardcoded darwin condition would then - # inject a conflicting --target=arm64-apple-darwin over whatever the - # wrapper set for itself. - if $(command) && ! [ feature.get-values : $(options) ] + if $(command) { - local machine = [ MATCH "^([^ ]+)" : - [ SHELL "$(command-string) -dumpmachine" ] ] ; - local target-os ; - switch $(machine:L) - { - case *android* : target-os ?= android ; - case *linux* : target-os ?= linux ; - case *darwin* : target-os ?= darwin ; - case *freebsd* : target-os ?= freebsd ; - case *solaris* : target-os ?= solaris ; - case *qnx* : target-os ?= qnxnto ; - } - if $(target-os) - { - local conditionx = [ regex.replace $(condition) "/" "," ] ; - toolset.add-defaults $(conditionx)\:$(target-os) ; - } + clang.set-target-os-default clang-darwin : $(condition) : $(command-string) : $(options) ; } clang.init-flags clang-darwin : $(condition) : $(version) : diff --git a/src/tools/clang-linux.jam b/src/tools/clang-linux.jam index 5e64bc288a..38918f84d5 100644 --- a/src/tools/clang-linux.jam +++ b/src/tools/clang-linux.jam @@ -38,7 +38,6 @@ import numbers ; import os ; import property ; import rc ; -import regex ; import set ; feature.extend-subfeature toolset clang : platform : linux ; @@ -76,29 +75,9 @@ rule init ( version ? : command * : options * ) { common.handle-options clang-linux : $(condition) : $(command) : $(options) ; - # Autodetect target-os from the compiler's own triple, - # unless the toolset was already told what to target. - if $(command) && ! [ feature.get-values : $(options) ] + if $(command) { - local machine = [ MATCH "^([^ ]+)" : - [ SHELL "$(command-string) -dumpmachine" ] ] ; - local target-os ; - switch $(machine:L) - { - case *android* : target-os ?= android ; - case *mingw* : target-os ?= windows ; - case *cygwin* : target-os ?= cygwin ; - case *linux* : target-os ?= linux ; - case *darwin* : target-os ?= darwin ; - case *freebsd* : target-os ?= freebsd ; - case *solaris* : target-os ?= solaris ; - case *qnx* : target-os ?= qnxnto ; - } - if $(target-os) - { - local conditionx = [ regex.replace $(condition) "/" "," ] ; - toolset.add-defaults $(conditionx)\:$(target-os) ; - } + clang.set-target-os-default clang-linux : $(condition) : $(command-string) : $(options) ; } clang.init-flags clang-linux : $(condition) : $(version) : diff --git a/src/tools/clang.jam b/src/tools/clang.jam index b58aedb6bc..85acbb0e66 100644 --- a/src/tools/clang.jam +++ b/src/tools/clang.jam @@ -35,6 +35,34 @@ rule init ( * : * ) } +rule set-target-os-default ( toolset : condition * : command-string : options * ) +{ + # Autodetect target-os from the compiler's own triple, unless the + # toolset was already told what to target + if ! [ feature.get-values : $(options) ] + { + local machine = [ MATCH "^([^ ]+)" : + [ SHELL "$(command-string) -dumpmachine" ] ] ; + local target-os ; + switch $(machine:L) + { + case *android* : target-os ?= android ; + case *mingw* : target-os ?= windows ; + case *cygwin* : target-os ?= cygwin ; + case *linux* : target-os ?= linux ; + case *darwin* : target-os ?= darwin ; + case *freebsd* : target-os ?= freebsd ; + case *solaris* : target-os ?= solaris ; + case *qnx* : target-os ?= qnxnto ; + } + if $(target-os) + { + local conditionx = [ regex.replace $(condition) "/" "," ] ; + toolset.add-defaults $(conditionx)\:$(target-os) ; + } + } +} + local rule cxxstd-flags ( toolset : condition * : options * ) { toolset.flags $(toolset).compile.c++ OPTIONS $(condition) : $(options) : unchecked ; From 86cc0ad9a494207393d15a8e6370b0f2bfd03d6b Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Mon, 10 Aug 2026 10:51:56 +0200 Subject: [PATCH 4/6] Add test to validate target-os autodetect Signed-off-by: Uilian Ries --- test/test_all.py | 1 + test/toolset_target_os_autodetect.py | 120 +++++++++++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 test/toolset_target_os_autodetect.py diff --git a/test/test_all.py b/test/test_all.py index af5354636f..66936735d5 100755 --- a/test/test_all.py +++ b/test/test_all.py @@ -486,6 +486,7 @@ def reorder_tests(tests, first_test): "toolset_intel_darwin", "toolset_msvc", "toolset_requirements", + "toolset_target_os_autodetect", "transitive_skip", "unit_test", "unused", diff --git a/test/toolset_target_os_autodetect.py b/test/toolset_target_os_autodetect.py new file mode 100644 index 0000000000..35d34c6e52 --- /dev/null +++ b/test/toolset_target_os_autodetect.py @@ -0,0 +1,120 @@ +#!/usr/bin/env python3 +# +# Distributed under the Boost Software License, Version 1.0. +# (See accompanying file LICENSE.txt or copy at +# https://www.bfgroup.xyz/b2/LICENSE.txt) + +# Test for autodetecting from the compiler's own +# `-dumpmachine` triple when target-os is not given explicitly, covering +# the gcc, clang-linux and clang-darwin toolsets. + +import BoostBuild +import sys +import textwrap + +MOCK_COMPILER_TEMPLATE = '''#!/usr/bin/env python3 +import sys + +args = sys.argv[1:] + +if args == ["-dumpmachine"]: + print("@TRIPLE@") + sys.exit(0) + +if args == ["-print-prog-name=ar"]: + print("ar") + sys.exit(0) + +if "-c" in args and "-o" in args: + if "-DOS_AUTODETECTED_OK" not in args: + sys.exit(1) + with open(args[args.index("-o") + 1], "w") as f: + f.write("mock object\\n") + sys.exit(0) + +sys.exit(1) +''' + + +def test_target_os_gcc_autodetect(): + t = BoostBuild.Tester(pass_toolset=0) + + t.write("fake-compiler.py", MOCK_COMPILER_TEMPLATE.replace("@TRIPLE@", "arm-linux-androideabi")) + t.write("project-config.jam", textwrap.dedent(''' + import os ; + path-constant HERE : . ; + local PYTHON = [ os.environ PYTHON_CMD ] ; + using gcc : autodetect : $(PYTHON) $(HERE)/fake-compiler.py ; + ''')) + t.write("Jamroot.jam", textwrap.dedent(''' + obj test : test.cpp : + android:OS_AUTODETECTED_OK ; + ''')) + t.write("test.cpp", "int f() { return 0; }") + + t.run_build_system([f"-sPYTHON_CMD={sys.executable}", "toolset=gcc-autodetect", "test"]) + t.cleanup() + +def test_target_os_clang_linux_autodetect(): + t = BoostBuild.Tester(pass_toolset=0) + + t.write("fake-compiler.py", MOCK_COMPILER_TEMPLATE.replace("@TRIPLE@", "aarch64-linux-android21")) + t.write("project-config.jam", textwrap.dedent(''' + import os ; + path-constant HERE : . ; + local PYTHON = [ os.environ PYTHON_CMD ] ; + using clang-linux : autodetect : $(PYTHON) $(HERE)/fake-compiler.py ; + ''')) + t.write("Jamroot.jam", textwrap.dedent(''' + obj test : test.cpp : + android:OS_AUTODETECTED_OK ; + ''')) + t.write("test.cpp", "int f() { return 0; }") + + t.run_build_system([f"-sPYTHON_CMD={sys.executable}", "toolset=clang-linux-autodetect", "test"]) + t.cleanup() + +def test_target_os_clang_darwin_autodetect(): + t = BoostBuild.Tester(pass_toolset=0) + + t.write("fake-compiler.py", MOCK_COMPILER_TEMPLATE.replace("@TRIPLE@", "x86_64-pc-solaris2.11")) + t.write("project-config.jam", textwrap.dedent(''' + import os ; + path-constant HERE : . ; + local PYTHON = [ os.environ PYTHON_CMD ] ; + using clang-darwin : autodetect : $(PYTHON) $(HERE)/fake-compiler.py ; + ''')) + t.write("Jamroot.jam", textwrap.dedent(''' + obj test : test.cpp : + solaris:OS_AUTODETECTED_OK ; + ''')) + t.write("test.cpp", "int f() { return 0; }") + + t.run_build_system([f"-sPYTHON_CMD={sys.executable}", "toolset=clang-darwin-autodetect", "test"]) + t.cleanup() + + +def test_target_os_clang_darwin_autodetect_linux(): + t = BoostBuild.Tester(pass_toolset=0) + + t.write("fake-compiler.py", MOCK_COMPILER_TEMPLATE.replace("@TRIPLE@", "armv7-unknown-linux-gnueabihf")) + t.write("project-config.jam", textwrap.dedent(''' + import os ; + path-constant HERE : . ; + local PYTHON = [ os.environ PYTHON_CMD ] ; + using clang-darwin : autodetect : $(PYTHON) $(HERE)/fake-compiler.py ; + ''')) + t.write("Jamroot.jam", textwrap.dedent(''' + obj test : test.cpp : + linux:OS_AUTODETECTED_OK ; + ''')) + t.write("test.cpp", "int f() { return 0; }") + + t.run_build_system([f"-sPYTHON_CMD={sys.executable}", "toolset=clang-darwin-autodetect", "test"]) + t.cleanup() + + +test_target_os_gcc_autodetect() +test_target_os_clang_linux_autodetect() +test_target_os_clang_darwin_autodetect() +test_target_os_clang_darwin_autodetect_linux() From 67e0e2c9041c01036e360f779b4f0d3a40791fe3 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Tue, 11 Aug 2026 10:26:15 +0200 Subject: [PATCH 5/6] Cover apple embedded platforms Signed-off-by: Uilian Ries --- src/tools/clang.jam | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/tools/clang.jam b/src/tools/clang.jam index 85acbb0e66..8a38f6d734 100644 --- a/src/tools/clang.jam +++ b/src/tools/clang.jam @@ -50,6 +50,9 @@ rule set-target-os-default ( toolset : condition * : command-string : options * case *mingw* : target-os ?= windows ; case *cygwin* : target-os ?= cygwin ; case *linux* : target-os ?= linux ; + case *tvos* : target-os ?= appletv ; + case *watchos* : target-os ?= iphone ; + case *ios* : target-os ?= iphone ; case *darwin* : target-os ?= darwin ; case *freebsd* : target-os ?= freebsd ; case *solaris* : target-os ?= solaris ; From 810fd560e8686561ebeccfdd46ae7b80377a232d Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 12 Aug 2026 07:57:13 +0200 Subject: [PATCH 6/6] Fix test to be compatible with old python Signed-off-by: Uilian Ries --- test/toolset_target_os_autodetect.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test/toolset_target_os_autodetect.py b/test/toolset_target_os_autodetect.py index 35d34c6e52..7ad7ae56ef 100644 --- a/test/toolset_target_os_autodetect.py +++ b/test/toolset_target_os_autodetect.py @@ -52,7 +52,7 @@ def test_target_os_gcc_autodetect(): ''')) t.write("test.cpp", "int f() { return 0; }") - t.run_build_system([f"-sPYTHON_CMD={sys.executable}", "toolset=gcc-autodetect", "test"]) + t.run_build_system(["-sPYTHON_CMD=" + sys.executable, "toolset=gcc-autodetect", "test"]) t.cleanup() def test_target_os_clang_linux_autodetect(): @@ -71,7 +71,7 @@ def test_target_os_clang_linux_autodetect(): ''')) t.write("test.cpp", "int f() { return 0; }") - t.run_build_system([f"-sPYTHON_CMD={sys.executable}", "toolset=clang-linux-autodetect", "test"]) + t.run_build_system(["-sPYTHON_CMD=" + sys.executable, "toolset=clang-linux-autodetect", "test"]) t.cleanup() def test_target_os_clang_darwin_autodetect(): @@ -90,7 +90,7 @@ def test_target_os_clang_darwin_autodetect(): ''')) t.write("test.cpp", "int f() { return 0; }") - t.run_build_system([f"-sPYTHON_CMD={sys.executable}", "toolset=clang-darwin-autodetect", "test"]) + t.run_build_system(["-sPYTHON_CMD=" + sys.executable, "toolset=clang-darwin-autodetect", "test"]) t.cleanup() @@ -110,7 +110,7 @@ def test_target_os_clang_darwin_autodetect_linux(): ''')) t.write("test.cpp", "int f() { return 0; }") - t.run_build_system([f"-sPYTHON_CMD={sys.executable}", "toolset=clang-darwin-autodetect", "test"]) + t.run_build_system(["-sPYTHON_CMD=" + sys.executable, "toolset=clang-darwin-autodetect", "test"]) t.cleanup()