This is an automated email from the ASF dual-hosted git repository.

sjanc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git

commit 410d8485a8669925b516297e54a31bd5a4288215
Author: Szymon Janc <[email protected]>
AuthorDate: Wed Oct 21 21:23:43 2026 +0200

    newt/builder: Link with C++ compiler if build has C++ sources
    
    The elf was always linked with compiler.path.cc. If any package
    contains C++ sources this fails, as gcc does not link the C++ runtime
    libraries:
    
      undefined reference to `operator new(unsigned long)'
      undefined reference to `__gxx_personality_v0'
    
    Track whether the build compiled any (not ignored) C++ source and link
    with compiler.path.cpp in that case, which selects the right libraries
    by default. The generated CMakeLists.txt sets LINKER_LANGUAGE to CXX
    accordingly. C-only builds are still linked with compiler.path.cc.
    
    Assisted-by: Claude:claude-opus-5-5
---
 newt/builder/build.go      | 12 ++++++++++++
 newt/builder/cmake.go      | 20 +++++++++++++++++---
 newt/toolchain/compiler.go | 19 +++++++++++++++++--
 3 files changed, 46 insertions(+), 5 deletions(-)

diff --git a/newt/builder/build.go b/newt/builder/build.go
index 26d7cf75..3c2bade8 100644
--- a/newt/builder/build.go
+++ b/newt/builder/build.go
@@ -60,6 +60,9 @@ type Builder struct {
        linkElf          string
        injectedSettings map[string]string
        modifiedExtRepos []string
+
+       // Whether the last build compiled any C++ sources.
+       hasCxx bool
 }
 
 func NewBuilder(
@@ -496,6 +499,7 @@ func (b *Builder) link(elfName string, linkerScripts 
[]string,
        }
 
        c.LinkerScripts = linkerScripts
+       c.LinkCxx = b.hasCxx
        c.AutogeneratedLinkerIncludeDir, err = 
b.GetAutogeneratedLinkerIncludeDir()
        if err != nil {
                return err
@@ -706,6 +710,7 @@ func (b *Builder) Build() error {
        // needs to be compiled.
        entries := []toolchain.CompilerJob{}
        bpkgCompilerMap := map[*BuildPackage]*toolchain.Compiler{}
+       b.hasCxx = false
        for _, bpkg := range bpkgs {
                subEntries, err := b.collectCompileEntriesBpkg(bpkg)
                if err != nil {
@@ -713,6 +718,13 @@ func (b *Builder) Build() error {
                }
                entries = append(entries, subEntries...)
 
+               for _, entry := range subEntries {
+                       if entry.CompilerType == toolchain.COMPILER_TYPE_CPP &&
+                               
!entry.Compiler.ShouldIgnoreFile(entry.Filename) {
+                               b.hasCxx = true
+                       }
+               }
+
                b.modifiedExtRepos = append(b.modifiedExtRepos, 
bpkg.getModifiedReposNames()...)
 
                if len(subEntries) > 0 {
diff --git a/newt/builder/cmake.go b/newt/builder/cmake.go
index af95634e..ba732998 100644
--- a/newt/builder/cmake.go
+++ b/newt/builder/cmake.go
@@ -176,6 +176,10 @@ func (b *Builder) CMakeBuildPackageWrite(w io.Writer, bpkg 
*BuildPackage,
                        continue
                }
 
+               if s.CompilerType == toolchain.COMPILER_TYPE_CPP {
+                       b.hasCxx = true
+               }
+
                if s.CompilerType == toolchain.COMPILER_TYPE_ARCHIVE {
                        arFile := trimProjectPath(s.Filename)
                        linkDirs = append(linkDirs, filepath.Dir(arFile))
@@ -229,6 +233,7 @@ func (b *Builder) CMakeTargetWrite(w io.Writer, 
targetCompiler *toolchain.Compil
        c.AddInfo(b.GetCompilerInfo())
 
        builtPackages := []*BuildPackage{}
+       b.hasCxx = false
        for _, bpkg := range bpkgs {
                builtPackage, err := b.CMakeBuildPackageWrite(w, bpkg,
                        &linkFlags, &libraries)
@@ -306,6 +311,13 @@ func (b *Builder) CMakeTargetWrite(w io.Writer, 
targetCompiler *toolchain.Compil
        cxxFlags = toolchain.SortFlags(cxxFlags...)
        lFlags = append(lFlags, cxxFlags...)
 
+       // Link with the C++ driver if there are C++ sources, so that the C++
+       // runtime libraries are linked in by default.
+       linkerLang := "C"
+       if b.hasCxx {
+               linkerLang = "CXX"
+       }
+
        fmt.Fprintf(w,
                `set_target_properties(%s
                       PROPERTIES
@@ -313,18 +325,20 @@ func (b *Builder) CMakeTargetWrite(w io.Writer, 
targetCompiler *toolchain.Compil
                       LIBRARY_OUTPUT_DIRECTORY %s
                       RUNTIME_OUTPUT_DIRECTORY %s
                       LINK_FLAGS "%s"
-                      LINKER_LANGUAGE C)`,
+                      LINKER_LANGUAGE %s)`,
                elfName,
                elfOutputDir,
                elfOutputDir,
                elfOutputDir,
-               strings.Join(escapeFlagsSlice(lFlags), " "))
+               strings.Join(escapeFlagsSlice(lFlags), " "),
+               linkerLang)
 
        fmt.Fprintln(w)
 
        libs := strings.Join(getLibsFromLinkerFlags(lFlags), " ")
        fmt.Fprintf(w, "# Workaround for gcc linker woes\n")
-       fmt.Fprintf(w, "set(CMAKE_C_LINK_EXECUTABLE 
\"${CMAKE_C_LINK_EXECUTABLE} %s\")\n", libs)
+       fmt.Fprintf(w, "set(CMAKE_%s_LINK_EXECUTABLE 
\"${CMAKE_%s_LINK_EXECUTABLE} %s\")\n",
+               linkerLang, linkerLang, libs)
        fmt.Fprintln(w)
 
        return nil
diff --git a/newt/toolchain/compiler.go b/newt/toolchain/compiler.go
index 80855c04..0ee968ae 100644
--- a/newt/toolchain/compiler.go
+++ b/newt/toolchain/compiler.go
@@ -78,6 +78,11 @@ type Compiler struct {
        LinkerScripts                 []string
        AutogeneratedLinkerIncludeDir string
 
+       // Link with the C++ compiler driver instead of the C one, so that the 
C++
+       // runtime libraries are linked in by default.  Set when the build
+       // contains C++ sources.
+       LinkCxx bool
+
        // Needs to be locked whenever a mutable field in this struct is 
accessed
        // during a build: objPathList, compileCommands and the dependency
        // tracker's most recent file data.
@@ -1191,8 +1196,9 @@ func (c *Compiler) CompileBinaryCmd(dstFile string, 
options map[string]bool,
 
        libList := c.getStaticLibs(util.UniqueStaticLib(staticLib))
 
+       linkerPath, _ := c.linkerPath()
        cmd := []string{
-               c.ccPath,
+               linkerPath,
                "-o",
                dstFile,
        }
@@ -1242,6 +1248,15 @@ func (c *Compiler) CompileBinaryCmd(dstFile string, 
options map[string]bool,
        return cmd
 }
 
+// Returns the compiler driver used for linking and its compiler.yml key.
+func (c *Compiler) linkerPath() (string, string) {
+       if c.LinkCxx {
+               return c.cppPath, "compiler.path.cpp"
+       }
+
+       return c.ccPath, "compiler.path.cc"
+}
+
 // Links the specified elf file.
 //
 // @param dstFile               The filename of the destination elf file to
@@ -1255,7 +1270,7 @@ func (c *Compiler) CompileBinary(dstFile string, options 
map[string]bool,
        // Make sure the compiler package info is added to the global set.
        c.ensureLclInfoAdded()
 
-       if err := c.checkToolPath(c.ccPath, "compiler.path.cc"); err != nil {
+       if err := c.checkToolPath(c.linkerPath()); err != nil {
                return err
        }
 

Reply via email to