I have been working on a 32-bit operating system project written in C using GNU LD version 2.34 as the linker.
As part of the build process, I use the following command:
ld -m elf_i386 -nostdlib -T ld/loader.ld build/bootloader/loader.o build/bootloader/loader.elf -o loader_full.elf
When using GNU LD version 2.34, this command succeeds. However, when I use a version higher than this, I get the following error:
ld: cannot use executable file 'build/bootloader/loader.elf' as input to a link
If necessary, here is the full Makefile script:
CC_FLAGS = -g -m32 -ffreestanding -nostartfiles -nostdlib -fno-stack-protector
LD_FLAGS = -m elf_i386 -nostdlib
CC := gcc ${CC_FLAGS}
LD := ld ${LD_FLAGS}
BOOTLOADER_DRIVERS = kernel/drivers/disk/ata.c kernel/drivers/io/screen.c kernel/drivers/utils/mem.c kernel/drivers/utils/ports.c
raw: prep os-image.bin
convert_vmdk: os-image.vmdk
all: prep os-image.bin
ESFS_raw_write: ESFS_raw_write.c
gcc $^ -o $#
# run OS in QEMU
run:
qemu-system-i386 -drive format=raw,file=os-image.bin
# assemble boot sector
build/bootloader/boot_sect.bin: boot/boot_sect.asm
nasm $^ -f bin -o $#
# compile second stage bootloader
build/bootloader/loader_2.o build/drivers/*.o: boot/*.c ${BOOTLOADER_DRIVERS}
${CC} -c $^
mv loader.o build/bootloader/loader_2.o
mv *.o build/drivers/
# link object files into kernel loader
build/bootloader/loader.elf: build/bootloader/loader_2.o build/drivers/*.o
${LD} -T ld/loader.ld $^ -o $#
rm build/bootloader/loader_2.o
# assemble first stage bootloader
build/bootloader/loader.o: boot/loader.asm
nasm $^ -f elf -o $#
# link first and second stage bootloaders
build/bootloader/loader_full.elf: build/bootloader/loader.o build/bootloader/loader.elf
${LD} -T ld/loader.ld $^ -o $#
# make bootloader binary file
build/bootloader/loader.bin: build/bootloader/loader_full.elf
objcopy $^ -O binary $#
./scripts/pad_loader.sh
# clean up unnecessary files
# rm build/bootloader/*.o build/bootloader/*.elf build/drivers/*.o
build/kernel/interrupt.o: kernel/cpu/interrupt.asm
nasm $^ -f elf -o $#
# compile kernel & write to 10MB raw drive image
build/kernel/hdd.bin: kernel/drivers/*/*.c kernel/cpu/*.c kernel/libc/*.c build/kernel/interrupt.o kernel/*.c
${CC} $^ -o build/kernel/kernel.o -T ld/kernel.ld
./scripts/write_kernel_to_drive.sh
# concat 3 boot stages into os-image file
os-image.bin: build/bootloader/boot_sect.bin build/bootloader/loader.bin build/kernel/hdd.bin
cat $^ > $#
os-image.vmdk:
VBoxManage convertfromraw os-image.bin os-image.vmdk --format VMDK
VBoxManage internalcommands sethduuid /home/tim/Dev/OSDev/os-image.vmdk 6372c00a-a62e-4241-9a21-90fa4c22f019
# prepare directory structure for build process
prep:
mkdir -p build/bootloader
mkdir -p build/drivers
mkdir -p build/kernel
# clean up build files and os-image binary
clean:
-rm -rf build/
-rm *.bin *.vmdk
-rm ESFS_raw_write
The project is also on GitHub, so you can build it for yourself:
http://github.com/TimCve/OSDev.git
I have just come up with a similar problem.
It seems ld version GNU ld (GNU Binutils) 2.36.1 links the file into an executable format.
To fix it, add -r in your ld command to output a relocatable format file.
From the ld manual:
-r
--relocateable
Generate relocatable output--i.e., generate an output file that can in turn serve as input to ld. This is often called partial linking. As a side effect, in environments that support standard Unix magic numbers, this option also sets the output file's magic number to OMAGIC. If this option is not specified, an absolute file is produced. When linking C++ programs, this option will not resolve references to constructors; to do that, use -Ur. This option does the same thing as -i.
It's not that ld can't take ELF files as input. It's that it won't take executable files as input. The error is:
ld: cannot use executable file '...' as input to a link
See https://sourceware.org/bugzilla/show_bug.cgi?id=26223
Does it work to simply use chmod -x $# after building the .elf file?
In my (eclipse-based) multicore MCUXpresso project, I had to add this line to my post-build steps to modify a byte inside of the generated "*.o" file so the linker step which used that file wouldn't complain anymore. This happened after I updated to version 11.6 which includes the LD version mentioned previously. I originally found this on the forums for NXP MCUXpresso, but I assume it will work similarly for just about anyone:
dd if=/dev/zero of="${BuildArtifactFileName}.o" bs=1 seek=16 conv=notrunc count=2
NXP MCUXpresso fix
I am trying to interface ssd1963 LCD with Raspberry Pi3 model B+, by following this guide on Github.
https://github.com/matusnovak/rpi-tftgl
While trying to install the makefile provided for rpi-tftgl in rpi-tftgl/tftgl directory I am getting this error when I run make command.
Here is the link of my captured image of pi terminal window showing the exact error:
Following is the error i recieved when I execute make command :
gcc -c src/tftgl.c -o src/tftgl.o -I/opt/vc/include -I. -Iinclude -D:0 -O3
<command-line>:0:1: error: macro names must be identifiers
Makefile:18: recipe for target 'src/tftgl.o' failed
make: *** [src/tftgl.o] Error 1
Can I get a solution for this or any recommendation for any other source or links which I can follow to interface ssd1963 LCD with touch enabled with Raspberrypi3.
Adding the makefile,
CC=gcc
AR=ar
DISPLAY?=ERROR
CFLAGS=-I/opt/vc/include -I. -Iinclude -D$(DISPLAY) -O3
prefix?=/usr/local
.PHONY: default all clean
default: tftgl
all: default
tftgl: libtftgl.a
libtftgl.a: src/tftgl.o
$(AR) rcs libtftgl.a src/tftgl.o
src/tftgl.o: src/tftgl.c src/tftgl_ssd1963.h src/tftgl_ads7843.h
$(CC) -c src/tftgl.c -o src/tftgl.o $(CFLAGS)
install: tftgl
install -m 0755 libtftgl.a $(prefix)/lib
install -m 0644 include/tftgl.h $(prefix)/include
clean:
-rm -f src/*.o
-rm -f libtftgl.a
I am providing here link to tftgl.c,
https://github.com/matusnovak/rpi-tftgl/blob/master/tftgl/src/tftgl.c
The (writer of) the Makefile doesn't take into account that the environment variable DISPLAY can be defined to something else than a macro definition. As it's not documented whether and how you'd need to define it, the best you can do is to make with the variable unset:
(unset DISPLAY; make)
If you prefer to change the makefile, just remove the ? from DISPLAY?=ERROR, leaving DISPLAY=ERROR.
I've been trying to get the following makefile to work.
INCLUDE=Include/
LIBRARY=Lib/
CC=g++
UNAME_S := $(shell uname -s)
ifeq ($(UNAME_S),Darwin)
LIBRARIES=-lGLEW -framework OpenGL -framework GLUT
else
LIBRARIES=-lGL -lglut -lGLEW
endif
SRC := $(shell find -name *.cpp | tr '\n' ' ')
all: release debug
.PHONY: init
init:
#mkdir -p build/release/object
#mkdir -p build/debug/object
debug: init
debug: CC = g++ -g
debug: BUILD_DIR = build/debug
debug: makegeneral
release: init
release: CC = g++
release: BUILD_DIR = build/release
release: makegeneral
makegeneral: OBJ = $(SRC:./src/%.cpp=$(BUILD_DIR)/object/%.o)
makegeneral: $(OBJ)
$(CC) -I$(INCLUDE) -L$(LIBRARY) $(OBJ) $(LIBRARIES) -o VoxPop
#rm -rf $(BUILD_DIR)/shaders
#mkdir -p $(BUILD_DIR)/shaders
#cp -r src/shaders/* $(BUILD_DIR)/shaders
$(BUILD_DIR)/object/%.o: src/%.cpp
$(CC) -I$(INCLUDE) -L$(LIBRARY) -o $# -c $<
.PHONY: clean
clean:
#rm build/debug/object/* build/release/object/*
Essentially, it sets a few variables specific to a debug build and a release build and then calls a common target, makegeneral. When I run make, I get the following output:
g++ -IInclude/ -LLib/ build/release/object/VoxPop.o build/release/object/Utils.o -lGL -lglut -lGLEW -o VoxPop
g++: error: build/release/object/VoxPop.o: No such file or directory
g++: error: build/release/object/Utils.o: No such file or directory
make: *** [makegeneral] Error 1
When I echo out SRC and OBJ at the beginning of makegeneral, they appear to be correct. It seems that the problem is with the dependencies for makegeneral, since the rule for compiling object files is never invoked and no there is no "No rule to make target..." message spit out.
For reference, this is what I get when I echo out SRC and OBJ at the beginning of makegeneral.
SRC: ./src/VoxPop.cpp ./src/Utils.cpp
OBJ: build/release/object/VoxPop.o build/release/object/Utils.o
BUILD_DIR is not set at the top level so expands to the empty string in the pattern rule. This is also the reason (I believe) for why make isn't failing on unbuildable prereqs. There aren't even any rules for how to do so (beyond the built-in rules). (Though I don't have access to a machine with make at the moment to test my theories.)
I'm also don't believe (though I can't test at the moment) that make will run your makegeneral target twice in this configuration to get you what you want. I believe you will only get it run once with whichever target make chooses to build first (the first listed I believe so in this case release).
I have a working Makefile, but there is a warning that I couldn't fix.
#Use the g++ compiler
CC = g++
# Compiler flags:
# -Wall (most warnings enabled)
# -g (for debugging with gdb)
CFLAGS = -Wall
# Executable name:
TARGET = deque_adt
all: main.o deque_adt.o deque_adt
$(TARGET): main.o deque_adt.o
$(CC) $(CFLAGS) main.o deque_adt.o -o $(TARGET)
main.o: main.cpp deque_adt.h
$(CC) $(CFLAGS) main.cpp -c
deque_adt.o: deque_adt.cpp deque_adt.h
$(CC) $(CFLAGS) deque_adt.cpp -c
clean:
rm *.o *~ $(TARGET)
error:
make: Warning: File `main.cpp' has modification time 2.1e+04 s in the future
g++ -Wall main.cpp -c
g++ -Wall deque_adt.cpp -c
g++ -Wall main.o deque_adt.o -o deque_adt
make: warning: Clock skew detected. Your build may be incomplete.
Can someone help me out to figure out the problem? I have tried to switch between the elements but it still gives the same warning.
To expand on Ben Voigt's answer:
find /your/dir -type f -exec touch {} +
will update the timestamp on all files in the directory. You can then make clean && make again.
check your computer time. I had the same problem and the root cause was my computer time was in the past - when I update it, it was work perfectly.
That message is usually an indication that some of your files have modification times later than the current system time.
Chech if your system time is in the past. Example:
$ date
If so You have several ways to fix this. the easier one is to install an ntp server:
apt install ntp
Or
yum install ntp
Or ...
Regarding of your operating system (Ubuntu, Centos, ...etc)
just set your system date:
example
date -s "2 OCT 2006 18:00:00"
I've faced the same issue, did the below approach on Ubuntu 20.04 and it worked for me.
touch main_.cpp
cp main.cpp main_.cpp
rm main.cpp
mv main_.cpp main.cpp
How do I compile and upload Arduino sketches from the command line on Mac and Linux? I've installed the Arduino programming environment. Are there some sample makefiles anywhere?
There is a command-line Arduino toolkit named Ino. It just does that.
Compiling and uploading sketches (as apposed to C/C++ sources) on the command line (on Windows, Mac, and Linux) is supported directly via flags to the arduino executable since 1.5.0.
An ino can be compiled and uploaded with arduino --upload [sketch.ino]
Documentation
This is my boilerplate gnu make include for AVR projects, you may need to adapt some of it to fit your environment. It creates dependencies, has a host of standard gcc options I find useful or that optimize for size, as well as a library dir I use. I used this successfully to compile arduino software, I also previously hacked the PdePreprocessor in the arduino editor to be run from the command line to generate all the voodoo:
https://github.com/wesen/mididuino/blob/master/app/src/processing/app/preproc/PdePreprocessor.java
#
# generic AVR makefile
#
# (c) July 2011 - Manuel Odendahl - wesen#ruinwesen.com
#
# include this into your main Makefile, after having defined TARGET and TARGET_OBJS
all: $(TARGET).hex
CURDIR := $(dir $(lastword $(MAKEFILE_LIST)))
include $(CURDIR)MidiCtrl.mk
CC = avr-gcc
CXX = avr-g++
OBJCOPY = avr-objcopy
AVR_ARCH ?= atmega64
LDAVR_ARCH ?= avrmega64
FLASH_PROTOCOL = jtag2
CFLAGS += -Os -ffunction-sections -DAVR -I. -mmcu=$(AVR_ARCH) -mcall-prologues -fshort-enums -fpack-struct -Wall -Werror
CFLAGS += -Wall -DLITTLE_ENDIAN -g -flto
CFLAGS += no-tree-loop-optimize -ffreestanding -morder1 -funsigned-char -funsigned-bitfields -fshort-enums -fpack-struct
CFLAGS += -fdata-sections -fno-split-wide-types -fno-inline-small-functions -mcall-prologues
CLDFLAGS += -Wl,--relax,--gc-sections -ffunction-sections
CLDFLAGS += -mmcu=$(AVR_ARCH)
LDFLAGS = -m $(LDAVR_ARCH) -M
# generate list
# CFLAGS += -Wa,-adhlns=$#.lst
%.o: %.cpp
$(CXX) $(CXXFLAGS) -c $< -o $#
%.o: %.c
$(CC) $(CFLAGS) -c $< -o $#
%.o: %.s
$(CC) $(CFLAGS) -c $< -o $#
%.s: %.c
$(CC) -S $(CFLAGS) -fverbose-asm $< -o $#
%.o: %.S
$(CC) $(CFLAGS) -c $< -o $#
%.syx: %.hex
ihex2sysex $< $#
%.srec: %.elf
$(OBJCOPY) -j .text -j .data -O srec $< $#
%.hex: %.elf
$(OBJCOPY) -j .text -j .data -O ihex $< $#
%.ee_srec: %.elf
$(OBJCOPY) -j .eeprom --change-section-lma .eeprom=0 -O srec $< $#
AVR_BASE_DIR ?= $(abspath $(CURDIR)..)
AVR_LIB_DIR ?= $(AVR_BASE_DIR)/hardware/libraries
AVR_LIBS += CommonTools Midi
AVR_LIB_DIRS += $(foreach lib,$(AVR_LIBS),$(AVR_LIB_DIR)/$(lib))
AVR_INC_FLAGS += $(foreach dir,$(AVR_LIB_DIRS),-I$(dir))
AVR_OBJS += $(foreach dir,$(AVR_LIB_DIRS),$(foreach file,$(wildcard $(dir)/*.cpp),$(subst .cpp,.o,$(file))))
AVR_OBJS += $(foreach dir,$(AVR_LIB_DIRS),$(foreach file,$(filter-out $(AVR_HOST_EXCLUDE),$(wildcard $(dir)/*.c)),$(subst .c,.o,$(file))))
AVR_DEPS += $(subst .o,.d,$(AVR_OBJS))
# AVR_HOST_EXCLUDE can be used to exclude specific files later on
CXXFLAGS += $(AVR_INC_FLAGS)
CFLAGS += $(AVR_INC_FLAGS)
CXXFlags += -Werror -Wall
CFLAGS += -Werror -Wall
default: all
%.d:%.c
set -e; $(CC) -MM $(CFLAGS) $< \
| sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' > $# ; \
[ -s $# ] || rm -f $#
%.d:%.cpp
set -e; $(CXX) -MM $(CXXFLAGS) $< \
| sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' > $# ; \
[ -s $# ] || rm -f $#
%.host.d:%.c
set -e; $(CC) -MM $(CFLAGS) $< \
| sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' > $# ; \
[ -s $# ] || rm -f $#
%.host.d:%.cpp
set -e; $(CXX) -MM $(CXXFLAGS) $< \
| sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' > $# ; \
[ -s $# ] || rm -f $#
printlibs:
echo $(AVR_LIBS)
$(TARGET).elf: $(TARGET).o $(TARGET_OBJS) $(AVR_OBJS)
$(CXX) $(CLDFLAGS) -g -o $# $^
_clean:
- rm *.elf *.hex *.o .midictrl.flags
libclean:
rm -rf $(TARGET_OBJS) $(OBJS)
# concrete settings for development environment
UNAME=$(shell uname)
ISWIN=$(findstring CYGWIN,$(UNAME))
ISMAC=$(findstring Darwin,$(UNAME))
CC = avr-gcc
CXX = avr-g++
OBJCOPY = avr-objcopy
AVR_ARCH = atmega64
F_CPU = 16000000L
CORE = minicommand2
Official CLI tool
The arduino team is developing a cli client
https://github.com/arduino/arduino-cli
Announcement: https://blog.arduino.cc/2018/08/24/announcing-the-arduino-command-line-interface-cli/
You can do almost everything with this, from downloading boards and libraries, to compile and upload scripts. What's missing is the monitoring part.
To monitor in linux you can still use the commands stty to configure port and cat to read it.
stty -F /dev/ttyACM0 38400 # <-- Baud rate. The number in Serial.begin()
cat /dev/ttyACM0 # <-- Port
You can find the port with arduino-cli
arduino-cli board list
Full instructions in the Github repo and the man page:
$ arduino-cli Arduino Command Line Interface (arduino-cli).
Usage: arduino-cli [command]
Examples: arduino <command> [flags...]
Available Commands:
board Arduino board commands.
compile Compiles Arduino sketches.
config Arduino Configuration Commands.
core Arduino Core operations.
help Help about any command
lib Arduino commands about libraries.
sketch Arduino CLI Sketch Commands.
upload Upload Arduino sketches.
version Shows version number of Arduino CLI.
You need to actually create a viable cpp file out of your arduino sketch. The arduino environment does that for you automatically. One trick to get to those files is to open your arduino preferences.txt (it's in ~/Library/Arduino on the mac, I think in your Documents and Settings or Application Data on windows, don't remember exactly), and set build.verbose=true and upload.verbose=true. Start arduino, and compile your sketch (don't upload it). The console at the bottom will show you which files were compiled. You can now go to that directory, which will contain the cpp file, and compiled object files for all the core arduino objects. You can copy those into your project and use the cpp file to do further hacking. Let me know if you need more information about the Makefile, I can provide you with those I have.
You can actually use the arduino GUI to compile and upload, and set the editor to external in the preferences. That way, you can edit the C++ (PDE) files from xcode, and have arduino generate the actual CPP and build the whole shebang.
You can also use XCode to write plain C++/C for the arduino, using the avr-gcc compiler.
Have a look at: https://stackoverflow.com/a/8192762/153835
You can then use the plain avrdude upload tool to program the arduino. Have a look at: http://www.ladyada.net/library/arduino/bootloader.html
It used to be that the protocol spoken by Arduino was a modification of the STK500 protocol, and that only the avrdude bundled with arduino could speak it. I don't know if the mainstream avrdude was upgraded, or if you still have to resort to the avrdude inside the Arduino folder.
You can use biicode (it's a project I'm working in) which is based on CMake (but you don't actually need to write any cmake file) and is also a tool to manage Arduino libraries
It's main features are:
Dependencies resolution, transitively, as maven does, but without config files: reads dependencies directly from source code.
Central repository, anyone can upload their libraries. They can be explored, navigated and discovered in the web
Version control: it checks versions compatibility and allows safe updates of dependencies
You can use it with any text editor (it has optional eclipse integration)
It manages project setup and compilations, flashes generated firmware to the board
You can see a quick demo here and read more in the documentation.
If you can use cmake then there are some links in the same web (this and this for example). GNU makefile is a little bit different from cmake but nothing complicated. Just Google a little bit and you can find a lot of Makefile examples how to compile AVR code.
I use platformio, quite like it. It also has extensions into Visual Studio Code, so you can do everything from there. It has library manager and uploader built-in.
My setup is a NFS drive where I have the code, mounted on my linux laptop, and also mounted on my Raspberry Pi that sits next to my Arduino's.
When it's time to compile, I do so on my laptop, and as the RPi is next to the Arduino, I upload from there..
After installing and configuring, the basics are simple;
'platformio run' will compile your code.
'platformio run -t upload' will compile & upload.
I also have a bash function to upload without compiling;
function th(){
if [ "${1}" = "upload" ];then
if [ ! -f platformio.ini ]; then
echo platformio.ini not found
else
UPLOAD_PORT=`cat platformio.ini | grep upload_port | awk '{print $3}'`
if [ "${UPLOAD_PORT}" = "" ]; then
echo no upload port
else
if [ "${2}" != "" ]; then
FIRMWARE=${2}
else
#the firmware location seems to have moved
# FIRMWARE='.pioenvs/megaatmega2560/firmware.hex'
FIRMWARE='.pio/build/megaatmega2560/firmware.hex'
fi
if [ -f "${FIRMWARE}" ]; then
avrdude -v -p atmega2560 -C /home/stevenk/.platformio/packages/tool-avrdude/avrdude.conf -c wiring -b 115200 -D -P "${UPLOAD_PORT}" -U flash:w:$FIRMWARE:i
else
echo ${FIRMWARE} not found
fi
fi
fi
else
wget --timeout 8 -qO- http://192.168.178.212/$1
fi
}
If you do not insist on make there is also scons/sconstruct scons/sconstruct. Since this in basically written in Python it is much simpler to tweak than make. In addition it can be debugged with any Python debugger.
I have a makefile for Arduino which can be used to compile and upload Arduino (or plain AVR C) programs to Arduino.
Following are some of the important features of this makefile
Supports upload via Arduino as ISP or any programmer
Supports compiling plain AVR C programs
Supports user as well as system libraries.
Generate assembly and symbol files
Program using alternate Arduino core (like ATtiny or Arduino alternate cores)
There's an official Arduino CLI tool:
https://blog.arduino.cc/2021/02/15/arduino-cli-0-16-0-is-ready-for-you-all/?queryID=undefined
It works pretty well, in my opinion. The GitHub repo is here:
https://github.com/arduino/arduino-cli
It's version 0.16.0. so sort of beta, but not really....
You can find the libraries and sample codes included in the Arduino under "file->examples".