Problem building on arm on linux

Hi All,

Everything builds fine for the simulator build but the building the device build (arm), I get a couple of linking errors:

/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-abort.o): in function abort': /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/thumb/v7e-m+fp/hard/newlib/libc/stdlib/../../../../../../../../newlib/libc/stdlib/abort.c:59: undefined reference to _exit'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-signalr.o): in function _kill_r': /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/thumb/v7e-m+fp/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/signalr.c:53: undefined reference to _kill'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-signalr.o): in function _getpid_r': /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/thumb/v7e-m+fp/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/signalr.c:83: undefined reference to _getpid'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-writer.o): in function _write_r': /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/thumb/v7e-m+fp/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/writer.c:49: undefined reference to _write'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-closer.o): in function _close_r': /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/thumb/v7e-m+fp/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/closer.c:47: undefined reference to _close'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-fstatr.o): in function _fstat_r': /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/thumb/v7e-m+fp/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/fstatr.c:55: undefined reference to _fstat'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-isattyr.o): in function _isatty_r': /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/thumb/v7e-m+fp/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/isattyr.c:52: undefined reference to _isatty'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-lseekr.o): in function _lseek_r': /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/thumb/v7e-m+fp/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/lseekr.c:49: undefined reference to _lseek'
/usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/bin/ld: /usr/lib/gcc/arm-none-eabi/9.2.1/../../../arm-none-eabi/lib/thumb/v7e-m+fp/hard/libc.a(lib_a-readr.o): in function _read_r': /build/newlib-CVVEyx/newlib-3.3.0/build/arm-none-eabi/thumb/v7e-m+fp/hard/newlib/libc/reent/../../../../../../../../newlib/libc/reent/readr.c:49: undefined reference to _read'

Im not sure quite what is the problem. Im fairly certain my arm setup is correct, since CMake will make a test to make sure that the c compiler for arm works.
From what I've read on stackoverflow, this is a typical problem when building for a target device and the library its using dose'nt implement functions like read/write. My guess is that Im not getting the correct library when im linking?

All and any help is much appreciated.
Here is the cmake project:

cmake_minimum_required(VERSION 3.14)
set(CMAKE_C_STANDARD 11)

set(ENVSDK $ENV{PLAYDATE_SDK_PATH})

if (NOT ${ENVSDK} STREQUAL "")
# Convert path from Windows
file(TO_CMAKE_PATH ${ENVSDK} SDK)
else()
execute_process(
COMMAND bash -c "egrep '^\s*SDKRoot' $HOME/.Playdate/config"
COMMAND head -n 1
COMMAND cut -c9-
OUTPUT_VARIABLE SDK
OUTPUT_STRIP_TRAILING_WHITESPACE
)
endif()

if (NOT EXISTS ${SDK})
message(FATAL_ERROR "SDK Path not found; set ENV value PLAYDATE_SDK_PATH")
return()
endif()

set(CMAKE_CONFIGURATION_TYPES "Debug;Release")
set(CMAKE_XCODE_GENERATE_SCHEME TRUE)

Game Name Customization

set(PLAYDATE_GAME_NAME InvaderGame)
set(PLAYDATE_GAME_DEVICE InvaderGame_DEVICE)

project(${PLAYDATE_GAME_NAME} C ASM)

file(GLOB IMAGES
"Source/images/*"
)

if (TOOLCHAIN STREQUAL "armgcc")
add_executable(${PLAYDATE_GAME_DEVICE} ${SDK}/C_API/buildsupport/setup.c Source/main.c Source/game.c Source/pdGlobals.c Source/mathDefs.c Source/loadGfx.c
Source/collisionDetect.c Source/collisionHandle.c Source/projectile.c
Source/enemies.c Source/structs2D.c Source/player.c Source/gameWorld.c Source/gameSession.c)
else()
add_library(${PLAYDATE_GAME_NAME} SHARED Source/main.c Source/game.c Source/pdGlobals.c Source/mathDefs.c Source/loadGfx.c
Source/collisionDetect.c Source/collisionHandle.c Source/projectile.c
Source/enemies.c Source/structs2D.c Source/player.c Source/gameWorld.c Source/gameSession.c ${IMAGES})
endif()

include(${SDK}/C_API/buildsupport/playdate_game.cmake)

/Jimmie

Tried building one of the examples from the C API and it builds fine, so its not an environment issue

I think I found it myself. Its a call to sprintf that generates the linkage error.

I have'nt really found anything in the documentation that mentionts that calling sprintf is not allowed?

1 Like

Hi @JimmieJohnsson - that got me too, see String Manipulation when using the C API - #4 by Nic

(or switch to playdate->system->formatString(char **ret, const char *format, ...))

2 Likes

Thanks for the info! I actually ended up swapping in a homebrewn itoa function, but this seems like a better solution.

This is due to newlib not having implemented certain functions. This is an intended feature of newlib, because newlib wants to leave these details up to you.

You can include pdewnlib.c and pdnewlib.h from here.

1 Like