Skip to content

Conversation

@trns1997
Copy link
Contributor

@trns1997 trns1997 commented Sep 4, 2025

Note: Please adhere to Contributing Guidelines.

Closes #16973

Summary

make export currently fails with the warning:

cp: cannot stat '.../libs/libc/elf/gnu-elf.ld': No such file or directory

This happens because the file gnu-elf.ld was removed and replaced with gnu-elf.ld.in. The real gnu-elf.ld is now only generated when CONFIG_LIBC_MODLIB=y (via modlib).

However, tools/mkexport.sh still assumes that gnu-elf.ld always exists and tries to copy it unconditionally, leading to the error.

Impact

  • Removes the confusing “cannot stat gnu-elf.ld” error during make export.
  • No functional change for users who have CONFIG_LIBC_MODLIB=y (the generated gnu-elf.ld is still copied).
  • For users without CONFIG_LIBC_MODLIB, the .in template is exported in place of the missing file, ensuring the export step succeeds without error.

No impact on runtime behavior, build outputs, or compatibility.

Testing

  • Host: Ubuntu 22.04, gcc 11.4.0.

  • Target: stm32f4discovery:nsh.

  • Export no error with CONFIG_LIBC_MODLIB=n

  • Export no error with CONFIG_LIBC_MODLIB=y

@trns1997 trns1997 marked this pull request as draft September 4, 2025 19:32
@github-actions github-actions bot added Area: Tooling Size: XS The size of the change in this PR is very small labels Sep 4, 2025
@trns1997
Copy link
Contributor Author

trns1997 commented Sep 4, 2025

ping @acassis @leducp

@acassis acassis requested review from anchao and yf13 September 4, 2025 20:13
@anchao
Copy link
Contributor

anchao commented Sep 5, 2025

@trns1997 @acassis Thanks for your detailed analysis!

CONFIG_LIBC_MODLIB has been deprecated in commit #15765 and is now named
CONFIG_LIBC_MODLIB -> CONFIG_LIBC_ELF

On current architectures, gnu-elf.ld.in requires compiler preprocessing before use, so it cannot be simply copied:
https://github.com/apache/nuttx/blob/master/libs/libc/elf/Makefile#L25-L28

I have 2 suggestions for fixing this issue:

  1. Remove the check for CONFIG_LIBC_ELF and always generate gnu-elf.ld:
image
diff --git a/libs/libc/Makefile b/libs/libc/Makefile
index 33bcba86d0..00c2a4f8df 100644
--- a/libs/libc/Makefile
+++ b/libs/libc/Makefile
@@ -183,9 +183,7 @@ context:: bin kbin
 ifeq ($(CONFIG_LIBC_ZONEINFO_ROMFS),y)
        $(Q) $(MAKE) -C zoneinfo context BIN=$(BIN)
 endif
-ifeq ($(CONFIG_LIBC_ELF),y)
        $(Q) $(MAKE) -C elf context
-endif
 
 
 # Dependencies

  1. Add a check in mkexport.sh to only copy gnu-elf.ld if CONFIG_LIBC_ELF is enabled:
image
diff --git a/tools/mkexport.sh b/tools/mkexport.sh
index 9d8c42d9c6..7346716f75 100755
--- a/tools/mkexport.sh
+++ b/tools/mkexport.sh
@@ -123,6 +123,10 @@ if [ ! -z "${CONFIG_VERSION_STRING}" -a "${CONFIG_VERSION_STRING}" != "0.0" ]; t
   VERSION="-${CONFIG_VERSION_STRING}"
 fi
 
+# Get the config string
+
+source "${TOPDIR}/.config"
+
 # Create the export directory
 
 EXPORTSUBDIR="nuttx-export${VERSION}"
@@ -184,15 +188,19 @@ cp "${TOPDIR}/tools/incdir.c" "${EXPORTDIR}/tools/."
 
 # Copy the board specific linker if found, or use the default when not.
 
-APPLD=gnu-elf.ld
-if [ -f "${BOARDDIR}/scripts/${APPLD}" ]; then
-  cp -f "${BOARDDIR}/scripts/${APPLD}" "${EXPORTDIR}/scripts/."
-else
-  cp -f "${TOPDIR}/libs/libc/elf/${APPLD}" "${EXPORTDIR}/scripts/."
-fi
+if [ ! -z "${CONFIG_LIBC_ELF}" ]; then
+  APPLD=gnu-elf.ld
+  if [ -f "${BOARDDIR}/scripts/${APPLD}" ]; then
+    cp -f "${BOARDDIR}/scripts/${APPLD}" "${EXPORTDIR}/scripts/."
+  else
+    cp -f "${TOPDIR}/libs/libc/elf/${APPLD}" "${EXPORTDIR}/scripts/."
+  fi
 
-if [ "${NUTTX_BUILD}" = "kernel" ]; then
-  LDNAME=${APPLD}
+  if [ "${NUTTX_BUILD}" = "kernel" ]; then
+    LDNAME=${APPLD}
+  fi
+else
+  LDNAME=""
 fi
 
 # Copy the board config script

I prefer option 2 : ) . If you agree with either solution, please update the current PR.

@trns1997
Copy link
Contributor Author

trns1997 commented Sep 5, 2025

@anchao i prefere option 2 as well but doesn't this already do the trick:

APPLD=gnu-elf.ld

if [ -f "${BOARDDIR}/scripts/${APPLD}" ]; then
  cp -f "${BOARDDIR}/scripts/${APPLD}" "${EXPORTDIR}/scripts/."
elif [ -f "${TOPDIR}/libs/libc/elf/${APPLD}" ]; then
  cp -f "${TOPDIR}/libs/libc/elf/${APPLD}" "${EXPORTDIR}/scripts/."
fi

But maybe for clarity sake its better to check for the CONFIG_LIBC_ELF var.

@trns1997
Copy link
Contributor Author

trns1997 commented Sep 5, 2025

When running:

./tools/configure.sh -E -l stm32f4discovery:nsh && make export -j8

with set -e enabled, the build stops with:

make: *** [tools/Unix.mk:781: export] Error 1

Verbose output shows the actual failure:

if [ -d "/home/thomas/nuttxspace/nuttx/nuttx-export-12.10.0/startup" ]; then \
  cp -f crt0.o "/home/thomas/nuttxspace/nuttx/nuttx-export-12.10.0/startup/."; \
else \
  echo "/home/thomas/nuttxspace/nuttx/nuttx-export-12.10.0/startup does not exist"; \
  exit 1; \
fi

it’s because the startup/ directory inside the export tree is never created, and the script exits when it tries to copy crt0.o there.

This looks to be the same root cause seen here in #16970 (comment) . Hopefully solving this will resolve both problems :)

@leducp
Copy link
Contributor

leducp commented Sep 5, 2025

What about adding a CI test linking a C++ helloworld with CMake to avoid regression in the future? (At least from a compile POV).

@trns1997
Copy link
Contributor Author

trns1997 commented Sep 5, 2025

What about adding a CI test linking a C++ helloworld with CMake to avoid regression in the future? (At least from a compile POV).

Totally agree, lets fix up all this get it functional, update the doc and then lets add a basic out of tree build test

@trns1997
Copy link
Contributor Author

trns1997 commented Sep 5, 2025

@leducp was right in comment: #16970 (comment). This commit is caused the issue. The commit moved/centralized crt0.c from arch/* into arch/common and builds crt0.o as part of libarch.a. That means __start is now provided both by board startup code (e.g. stm32_start.o in libarch.a) and by the exported crt0.o in startup/, which leads to a "multiple definition of __start" error when building apps against an export package. Updating the line 22 in scripts/toolchain.cmake from file(GLOB STARTUP_OBJS ${NUTTX_PATH}/startup/*) to set(STARTUP_OBJ ${NUTTX_PATH}/startup/crt0.o) forces the app to use crt0.o. I have the app that build in #16970 but not sure this is the correct expected solution. I would like someones input on this before i implement this fix.

@trns1997
Copy link
Contributor Author

trns1997 commented Sep 8, 2025

@leducp was right in comment: #16970 (comment). This commit is caused the issue. The commit moved/centralized crt0.c from arch/* into arch/common and builds crt0.o as part of libarch.a. That means __start is now provided both by board startup code (e.g. stm32_start.o in libarch.a) and by the exported crt0.o in startup/, which leads to a "multiple definition of __start" error when building apps against an export package. Updating the line 22 in scripts/toolchain.cmake from file(GLOB STARTUP_OBJS ${NUTTX_PATH}/startup/*) to set(STARTUP_OBJ ${NUTTX_PATH}/startup/crt0.o) forces the app to use crt0.o. I have the app that build in #16970 but not sure this is the correct expected solution. I would like someones input on this before i implement this fix.

@xiaoxiang781216 could we get your input on this?

@xiaoxiang781216
Copy link
Contributor

@anjiahao1 please take a look.

@github-actions github-actions bot added the Size: M The size of the change in this PR is medium label Sep 10, 2025
@trns1997 trns1997 marked this pull request as ready for review September 11, 2025 08:42
@trns1997
Copy link
Contributor Author

When running:

./tools/configure.sh -E -l stm32f4discovery:nsh && make export -j8

with set -e enabled, the build stops with:

make: *** [tools/Unix.mk:781: export] Error 1

Verbose output shows the actual failure:

if [ -d "/home/thomas/nuttxspace/nuttx/nuttx-export-12.10.0/startup" ]; then \
  cp -f crt0.o "/home/thomas/nuttxspace/nuttx/nuttx-export-12.10.0/startup/."; \
else \
  echo "/home/thomas/nuttxspace/nuttx/nuttx-export-12.10.0/startup does not exist"; \
  exit 1; \
fi

it’s because the startup/ directory inside the export tree is never created, and the script exits when it tries to copy crt0.o there.

This looks to be the same root cause seen here in #16970 (comment) . Hopefully solving this will resolve both problems :)

This wasn’t the actual root cause. The real issue was the use of 2>/dev/null, which was hiding the underlying error. I’ve updated the script to replace 2>/dev/null with checks, allowing us to use set -e. This ensures that any errors are caught immediately and helps prevent regressions in mkexport.sh. The next step will be to add an out-of-tree build test in CI to verify that the exported content continues to work over time.

@leducp
Copy link
Contributor

leducp commented Sep 12, 2025

Good work!

@trns1997 trns1997 force-pushed the fix-mkexport-missing-gnu branch 3 times, most recently from 7531c21 to 4fcd0d7 Compare September 12, 2025 07:46
Fix missing `gnu-elf.ld` file copy during export generation
and update `toolchain.cmake` script to ensure proper toolchain
detection and configuration.
* Prevents build failures when exporting projects.
* Improves reproducibility of generated exports.

Signed-off-by: trns1997 <trns1997@gmail.com>
@xiaoxiang781216 xiaoxiang781216 merged commit 918505e into apache:master Sep 14, 2025
39 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Area: Tooling Size: M The size of the change in this PR is medium Size: XS The size of the change in this PR is very small

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Non-blocking make export error: missing gnu-elf.ld

5 participants