Pass an extra parameter to make - linux

I have a Makefile like this:
baud=19200
src=dimmer
avrType=attiny13
programmerDev=/dev/ttyUSB003
programmerType=stk500v1
object:
avr-gcc -g -DF_CPU=$(avrFreq) -Wall -Os -mmcu=$(avrType) -c -o $(src).o $(src).cpp
read:
#for memory in calibration eeprom efuse flash fuse hfuse lfuse lock signature application apptable boot prodsig usersig; do \
avrdude -p $(avrType) -c$(programmerType) -P$(programmerDev) -b$(baud) -v -U $$memory:r:./$(avrType).$$memory.hex:i; \
done
Which works as intended. When I type make read several files are extracted from the microcontroller. This can take a little while because of the slow connection and data size, so I was thinking it would be nice to be able to just type make read flash, but I can't figure out how to do that.
Of course I can make entries like read_flash, read_hfuse ... but I have a feeling it can be done smarter.
I also want to be able to run a command like make read all which will execute every file in turn from the controller.
Now I am new to creating Makfile's, so maybe I am on the wrong track all together. Please feel free to explain how it should be done.
I am on Linux.

If a highly GNU-specific makefile is acceptable to you (and I'd argue that it's much better to use a portable make, such as GNU's, than writing portable makefiles), you can implement this rather easily:
ALL = calibration eeprom efuse flash fuse hfuse lfuse lock signature \
application apptable boot prodsig usersig
ifeq (read,$(firstword $(MAKECMDGOALS)))
WANT := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
ifneq ($(WANT),)
$(eval $(WANT):;#:)
endif
UNKNOWN := $(filter-out $(ALL),$(WANT))
ifneq ($(UNKNOWN),)
$(error Invalid arguments: $(UNKNOWN))
endif
endif
read-one = avrdude -p $(avrType) -c$(programmerType) -P$(programmerDev) \
-b$(baud) -v -U $1:r:./$(avrType).$1.hex:i
.PHONY: read
read:
$(foreach w,$(or $(WANT),$(ALL)),$(call read-one,$w) &&) :
If the first argument in the command line is "read", this sets the WANT variable to the list of arguments after the first. It then turns those names into no-op targets and makes the read target invoke the read-one function for each name, or for $(ALL) if no name was specified.
I use variations of this quite often, for things like make print VARIABLE..., which will just print $(VARIABLE) or make help TOPIC to display information about a target.

What about making the list of modules a configurable list with a default:
LIST = calibration eeprom efuse flash fuse \
hfuse lfuse lock signature application \
apptable boot prodsig usersig
read:
#for memory in $(LIST); do \
avrdude -p $(avrType) -c$(programmerType) -P$(programmerDev) \
-b$(baud) -v -U $$memory:r:./$(avrType).$$memory.hex:i; \
done
And then call make either as make for the default, or make LIST="eeprom efuse" for just two modules.

I would do: make flash or make hfuse or make all with the following Makefile:
baud=19200
avrType=attiny13
programmerDev=/dev/ttyUSB003
programmerType=stk500v1
all: calibration eeprom efuse flash fuse hfuse lfuse lock signature \
application apptable boot prodsig usersig
%:
avrdude -p $(avrType) -c$(programmerType) -P$(programmerDev) -b$(baud) \
-v -U $#:r:./$(avrType).$$memory.hex:i || rm ./$(avrType).$#.hex;
This is probably not portable Make, but it works in gnu make. This does not allow any other rules, but you could name this file read and do make -f read flash. That would allow other rules to be placed in other make files.
Notice that this is not particularly safe, since it will run avrdude on make foo. To get tighter control of the targets, you can do:
.SUFFIXES: .ph
.PHONY: efuse.ph eeprom.ph ...
all: efuse eeprom ...
.ph:
avrdude ...
This way, only the targets listed as PHONY will be valid targets.

Related

XDP program ip link error: Prog section rejected: Operation not permitted

I try to get into XDP, for this I have this very small program:
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include "bpf/bpf_helpers.h"
#include "xdpsock.h"
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, MAX_SOCKS);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
} xsks_map SEC(".maps");
SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx) {
return XDP_DROP;
}
But if I try to load it into a virtual interface veth-basic02, I get this error:
$ sudo ip -force link set dev veth-basic02 xdp object xdpsock_kern.o
section xdp_sock
Prog section 'xdp_sock' rejected: Operation not permitted (1)!
- Type: 6
- Instructions: 2 (0 over limit)
- License:
Verifier analysis:
Error fetching program/map!
Kernel-Version: 5.3.0-28-generic
This is the Makefile I am using:
OBJS = xdpsock_kern.o
LLC ?= llc
CLANG ?= clang
INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`
EXTRA_CFLAGS ?= -O2 -emit-llvm
# In case up-to-date headers are not installed locally in /usr/include,
# use source build.
linuxhdrs ?= /usr/src/linux-headers-5.1.0-050100
LINUXINCLUDE = -I$(linuxhdrs)/arch/x86/include/uapi \
-I$(linuxhdrs)/arch/x86/include/generated/uapi \
-I$(linuxhdrs)/include/generated/uapi \
-I$(linuxhdrs)/include/uapi \
-I$(linuxhdrs)/include \
-I/bpf
prefix ?= /usr/local
INSTALLPATH = $(prefix)/lib/bpf
install_PROGRAM = install
install_DIR = install -dv
all: $(OBJS)
.PHONY: clean
clean:
rm -f $(OBJS)
INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`
$(OBJS): %.o:%.c
$(CLANG) $(INC_FLAGS) \
-D__KERNEL__ -D__ASM_SYSREG_H \
-Wno-unused-value -Wno-pointer-sign \
-Wno-compare-distinct-pointer-types \
-Wno-gnu-variable-sized-type-not-at-end \
-Wno-address-of-packed-member -Wno-tautological-compare \
-Wno-unknown-warning-option \
-I../include $(LINUXINCLUDE) \
$(EXTRA_CFLAGS) -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $#
install: $(OBJS)
$(install_DIR) -d $(INSTALLPATH) ; \
$(install_PROGRAM) $^ -t $(INSTALLPATH)
uninstall: $(OBJS)
rm -rf $(INSTALLPATH)
Lockdown:
$ dmesg | grep Lockdown
[ 1.283355] Lockdown: swapper/0: Hibernation is restricted; see man kernel_lockdown.7
[ 11.313219] Lockdown: systemd: /dev/mem,kmem,port is restricted; see man kernel_lockdown.7
[ 11.337794] Lockdown: systemd: BPF is restricted; see man kernel_lockdown.7
[ 17.147844] Lockdown: Xorg: ioperm is restricted; see man kernel_lockdown.7
Edit:
echo 1 > /proc/sys/kernel/sysrq + echo x > /proc/sysrq-trigger + Alt+SysRq+x indeed solves the problem - I can finally load the XDP-Program! Funny easter egg though. Thank you #Qeole!
eBPF: Operation not permitted
There are several possible causes for a permission error (-EPERM returned by bpf(), which you can observe with strace -e bpf <command>) when working with eBPF. But no so many. Usually, they fall under one of the following items:
User does not have the required capabilities (CAP_SYS_ADMIN, CAP_NET_ADMIN, ... typically depending on the types of the programs being used). This is usually solved by running as root, who has all necessary capabilities. In your case you run with sudo, so you are covered.
Creating the BPF object (new map, or loading a program) would exceed the limit for the amount of memory that can be locked in the kernel by the user. This is usually solved (for root) by using ulimit -l <something_big> in the terminal, or setrlimit() in a C program. Very unlikely in your case, your program is very small and you did not mention having a lot of BPF objects loaded on your system.
There are a few more possibilies, like trying to write on maps that are “frozen” or read-only etc., or trying to use function calls for non-root users. These are usually for more advanced use cases and should not be hit with a program as simple as yours.
Lockdown, Secure Boot, EFI and (unfortunate) backports for bpf() restrictions
But the problem that you seem to be hitting could be related to something else. “Lockdown” is a security module that was merged into Linux 5.5 kernel. It aims at preventing users to modify the running Linux image. It turns out that several distributions decided to backport Lockdown to their kernels, and sometimes they picked patches that predated the final version that was merged to mainline Linux.
Ubuntu and Fedora, for example, have a bunch of custom patches to backport that feature to the kernels used in Disco/19.04 and Eoan/19.10 (kernel 5.3 for the latter, I don't remember for Disco). It includes a patch that completely disables the bpf() system call when Lockdown is activated, meaning that creating maps or loading BPF programs is not possible. Also, they enabled Lockdown by default when Secure Boot is activated, which, I think, is the default for machines booting with EFI.
See also this blog post: a good way to check if Lockdown is affecting your BPF usage is to try and load minimal programs, or to run dmesg | grep Lockdown to see if it says something like:
Lockdown: systemd: BPF is restricted; see man kernel_lockdown.7
So for Ubuntu 19.04 and 19.10, for example, you have to disable Lockdown to work with eBPF. This may be done with a physical stroke of the SysRq key + x (I have not tested), but NOT by writing to /proc/sysrq-trigger (Ubuntu disabled it for this operation). Alternatively, you can disable Secure Boot (in the BIOS or with mokutil, search for the relevant options on the Internet, and do not forget to check the security implications).
Note that Linux kernel 5.4 or newest has the mainline restrictions for bpf(), which do not deactivate the system call, so Focal/20.04 and newest will not be affected. Upgrading to a new kernel might thus be another workaround. I filed a ticket a few days ago to ask for this change to be backported (instead of deactivating bpf()) and the work is in progress, so by the time new readers look at the answer Lockdown impact on eBPF might well be mitigated (Edit: Should be fixed on Ubuntu 19.10 with kernel 5.3.0-43). Not sure how other distros handle this. And it will still have strong implications for tracing with eBPF, though.

AF_XDP not working on Kernel `4.18.0-25-generic` [duplicate]

I try to get into XDP, for this I have this very small program:
// SPDX-License-Identifier: GPL-2.0
#include <linux/bpf.h>
#include "bpf/bpf_helpers.h"
#include "xdpsock.h"
struct {
__uint(type, BPF_MAP_TYPE_ARRAY);
__uint(max_entries, MAX_SOCKS);
__uint(key_size, sizeof(int));
__uint(value_size, sizeof(int));
} xsks_map SEC(".maps");
SEC("xdp_sock") int xdp_sock_prog(struct xdp_md *ctx) {
return XDP_DROP;
}
But if I try to load it into a virtual interface veth-basic02, I get this error:
$ sudo ip -force link set dev veth-basic02 xdp object xdpsock_kern.o
section xdp_sock
Prog section 'xdp_sock' rejected: Operation not permitted (1)!
- Type: 6
- Instructions: 2 (0 over limit)
- License:
Verifier analysis:
Error fetching program/map!
Kernel-Version: 5.3.0-28-generic
This is the Makefile I am using:
OBJS = xdpsock_kern.o
LLC ?= llc
CLANG ?= clang
INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`
EXTRA_CFLAGS ?= -O2 -emit-llvm
# In case up-to-date headers are not installed locally in /usr/include,
# use source build.
linuxhdrs ?= /usr/src/linux-headers-5.1.0-050100
LINUXINCLUDE = -I$(linuxhdrs)/arch/x86/include/uapi \
-I$(linuxhdrs)/arch/x86/include/generated/uapi \
-I$(linuxhdrs)/include/generated/uapi \
-I$(linuxhdrs)/include/uapi \
-I$(linuxhdrs)/include \
-I/bpf
prefix ?= /usr/local
INSTALLPATH = $(prefix)/lib/bpf
install_PROGRAM = install
install_DIR = install -dv
all: $(OBJS)
.PHONY: clean
clean:
rm -f $(OBJS)
INC_FLAGS = -nostdinc -isystem `$(CLANG) -print-file-name=include`
$(OBJS): %.o:%.c
$(CLANG) $(INC_FLAGS) \
-D__KERNEL__ -D__ASM_SYSREG_H \
-Wno-unused-value -Wno-pointer-sign \
-Wno-compare-distinct-pointer-types \
-Wno-gnu-variable-sized-type-not-at-end \
-Wno-address-of-packed-member -Wno-tautological-compare \
-Wno-unknown-warning-option \
-I../include $(LINUXINCLUDE) \
$(EXTRA_CFLAGS) -c $< -o -| $(LLC) -march=bpf -filetype=obj -o $#
install: $(OBJS)
$(install_DIR) -d $(INSTALLPATH) ; \
$(install_PROGRAM) $^ -t $(INSTALLPATH)
uninstall: $(OBJS)
rm -rf $(INSTALLPATH)
Lockdown:
$ dmesg | grep Lockdown
[ 1.283355] Lockdown: swapper/0: Hibernation is restricted; see man kernel_lockdown.7
[ 11.313219] Lockdown: systemd: /dev/mem,kmem,port is restricted; see man kernel_lockdown.7
[ 11.337794] Lockdown: systemd: BPF is restricted; see man kernel_lockdown.7
[ 17.147844] Lockdown: Xorg: ioperm is restricted; see man kernel_lockdown.7
Edit:
echo 1 > /proc/sys/kernel/sysrq + echo x > /proc/sysrq-trigger + Alt+SysRq+x indeed solves the problem - I can finally load the XDP-Program! Funny easter egg though. Thank you #Qeole!
eBPF: Operation not permitted
There are several possible causes for a permission error (-EPERM returned by bpf(), which you can observe with strace -e bpf <command>) when working with eBPF. But no so many. Usually, they fall under one of the following items:
User does not have the required capabilities (CAP_SYS_ADMIN, CAP_NET_ADMIN, ... typically depending on the types of the programs being used). This is usually solved by running as root, who has all necessary capabilities. In your case you run with sudo, so you are covered.
Creating the BPF object (new map, or loading a program) would exceed the limit for the amount of memory that can be locked in the kernel by the user. This is usually solved (for root) by using ulimit -l <something_big> in the terminal, or setrlimit() in a C program. Very unlikely in your case, your program is very small and you did not mention having a lot of BPF objects loaded on your system.
There are a few more possibilies, like trying to write on maps that are “frozen” or read-only etc., or trying to use function calls for non-root users. These are usually for more advanced use cases and should not be hit with a program as simple as yours.
Lockdown, Secure Boot, EFI and (unfortunate) backports for bpf() restrictions
But the problem that you seem to be hitting could be related to something else. “Lockdown” is a security module that was merged into Linux 5.5 kernel. It aims at preventing users to modify the running Linux image. It turns out that several distributions decided to backport Lockdown to their kernels, and sometimes they picked patches that predated the final version that was merged to mainline Linux.
Ubuntu and Fedora, for example, have a bunch of custom patches to backport that feature to the kernels used in Disco/19.04 and Eoan/19.10 (kernel 5.3 for the latter, I don't remember for Disco). It includes a patch that completely disables the bpf() system call when Lockdown is activated, meaning that creating maps or loading BPF programs is not possible. Also, they enabled Lockdown by default when Secure Boot is activated, which, I think, is the default for machines booting with EFI.
See also this blog post: a good way to check if Lockdown is affecting your BPF usage is to try and load minimal programs, or to run dmesg | grep Lockdown to see if it says something like:
Lockdown: systemd: BPF is restricted; see man kernel_lockdown.7
So for Ubuntu 19.04 and 19.10, for example, you have to disable Lockdown to work with eBPF. This may be done with a physical stroke of the SysRq key + x (I have not tested), but NOT by writing to /proc/sysrq-trigger (Ubuntu disabled it for this operation). Alternatively, you can disable Secure Boot (in the BIOS or with mokutil, search for the relevant options on the Internet, and do not forget to check the security implications).
Note that Linux kernel 5.4 or newest has the mainline restrictions for bpf(), which do not deactivate the system call, so Focal/20.04 and newest will not be affected. Upgrading to a new kernel might thus be another workaround. I filed a ticket a few days ago to ask for this change to be backported (instead of deactivating bpf()) and the work is in progress, so by the time new readers look at the answer Lockdown impact on eBPF might well be mitigated (Edit: Should be fixed on Ubuntu 19.10 with kernel 5.3.0-43). Not sure how other distros handle this. And it will still have strong implications for tracing with eBPF, though.

FIPS Capable OpenSSL cross-compiled: incore fingerprint issue

I'm having an issue trying to use the OpenSSL shared library (libcrypto) compiled to be FIPS capable on a MIPS device.
I cross-compiled the FIPS Object Module and then the OpenSSL library in the following way (summarizing):
export FIPS_SIG=<my_path>/incore
./config fips --with-fipsdir=<my_path>/fips-2.0
make depend
make
make install
I did all the needed steps, so I'm able to compile and install the library.
The issue appears when I try to run the FIPS_mod_set(1) API from an application linking the OpenSSL library.
The FIPS mode initialization fails receiving this error:
2010346568:error:2D06B06F:lib(45):func(107):reason(111):NA:0:
Debugging the FIPS code, I found that the issue is inside the FIPS_check_incore_fingerprint(void) function:
the check memcmp(FIPS_signature,sig,sizeof(FIPS_signature)) fails.
Going deeper in the debug I discovered that the FIPS_signature value remains the default one, so I have the doubt that the incore script, called by the fipsld utility, is not embedding properly the fingerprint inside the OpenSSL shared object.
How can I check if the incore script embedded the fingerprint inside the shared object?
How can I print the expected fingerprint?
Do I need to adapt the incore script? (I suppose it's not allowed)
Do you have any suggestion?
Thanks a lot!
P.S.: I'm cross-compiling using an x86 Linux machine.
I found the issue! I'll try to explain the whole debugging process and the solution.
INTRODUCTION:
When OpenSSL is configured to be FIPS capable, during the compilation the Makefile calls a utility, fipsld, which both performs the check of the FIPS
Object Module and generates the new HMAC-SHA-1 digest for the application executable (as explained in the official OpenSSL user guide https://www.openssl.org/docs/fips/UserGuide-2.0.pdf)
The fipsld command requires that the CC and FIPSLD_CC environment variables be set,
with the latter taking precedence.
In the Makefile you will find something like this:
libcrypto$(SHLIB_EXT): libcrypto.a fips_premain_dso$(EXE_EXT)
#if [ "$(SHLIB_TARGET)" != "" ]; then \
if [ "$(FIPSCANLIB)" = "libcrypto" ]; then \
FIPSLD_LIBCRYPTO=libcrypto.a ; \
FIPSLD_CC="$(CC)"; CC=$(FIPSDIR)/bin/fipsld; \
export CC FIPSLD_CC FIPSLD_LIBCRYPTO; \
fi; \
$(MAKE) -e SHLIBDIRS=crypto CC="$${CC:-$(CC)}" build-shared && \
(touch -c fips_premain_dso$(EXE_EXT) || :); \
else \
echo "There's no support for shared libraries on this platform" >&2; \
exit 1; \
fi
Then, the fipsld utility invokes a shell script, incore, used to embed the FIPS Object Module's expected fingerprint in the OpenSSL shared object. It's important to specify the incore path via FIPS_SIG env variable, e.g.:
export FIPS_SIG=$PWD/openssl­fips­2.0/util/incore
DEBUGGING:
Debugging the incore script, I could see that the script tried to embed the signature into the shared object at the offset 0x001EE6B0 while the FIPS_signature symbol inside the shared object was located at a different offset, to be more specific at 0x001F0630:
objdump -t libcrypto.so.1.0.0 | grep FIPS_signature
001f0630 g O .data 00000014 FIPS_signature
readelf -a libcrypto.so.1.0.0 | grep FIPS_signature
870: 001f0630 20 OBJECT GLOBAL DEFAULT 18 FIPS_signature
3925: 001f0630 20 OBJECT GLOBAL DEFAULT 18 FIPS_signature
Furthermore dumping the shared object I wasn't able to find the generated signature at the offset 0x001EE6B0 so I reached the conclusion that the shared object was edited after the signature embedding procedure by some other process.
SOLUTION:
I was using a package Makefile for the OpenSSL packet formatted in the following way:
$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)
<options>
all
$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)
<options>
build-shared
rm $(PKG_BUILD_DIR)/libssl.so.*.*.*
$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)
<options>
do_linux-shared
$(MAKE) -C $(PKG_BUILD_DIR)
<options>
install
As suspected, make build-shared and make do_linux-shared commands were responsible for changing the shared object in the wrong way.
NOTICE that make build-shared was called without using the proper environment variables.
I changed the package Makefile:
$(MAKE) $(PKG_JOBS) -C $(PKG_BUILD_DIR)
<options>
all
$(MAKE) -C $(PKG_BUILD_DIR)
<options>
install
Now the FIPS_check_incore_fingerprint(void) function returns with success and everything is working fine!
NOTE:
The following guide for Android devices has been very useful to find the proper solution.
https://wiki.openssl.org/index.php/FIPS_Library_and_Android

How to add my own software to a Buildroot Linux package?

I am trying to add my own program to a small linux, created with Buildroot.
What I've done so far:
I've created a new directory inside my 'buildroot/package/' called 'HelloWorld'.
Inside 'buildroot/package/HelloWorld' I have : a Config.in, HelloWorld.mk and HelloWorld directory.
Config.in holds this:
config BR2_PACKAGE_HELLOWORLD
bool "helloworld"
default y
help
Hello world component.
HelloWorld.mk holds this:
HELLOWORLD_VERSION:= 1.0.0
HELLOWORLD_SITE:= /home/userpc/Downloads/helloworld/
HELLOWORLD_SITE_METHOD:=local
HELLOWORLD_INSTALL_TARGET:=YES
define HELLOWORLD_BUILD_CMDS
$(MAKE) CC="$(TARGET_CC)" LD="$(TARGET_LD)" -C $(#D) all
endef
define HELLOWORLD_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(#D)/helloworld $(TARGET_DIR)/bin
endef
define HELLOWORLD_PERMISSIONS
/bin/helloworld f 4755 0 0 - - - - -
endef
$(eval $(generic-package))
(inspiration source)
The HelloWorld directory contains: main.c & Makefile:
main.c :
#include <stdio.h>
int main()
{
printf("\nMain entry.\n");
return 0;
}
Makefile:
CC=gcc
CFLAGS=-I.
all: *.c
$(CC) -Os -Wall *.c -o helloworld
# $(STRIP) helloworld
clean:
rm -f a.out helloworld
rm -f *.o
Edit: And I have also added source "package/HelloWorld/Config.in" to 'package/Config.in'
But when I mount my rootfs.ext2 partition I can't find my HelloWorld executable inside /usr/bin .., I am really new to this and don't have any prior knowledge, so could you please explain to me, what am I missing from this, because I'm sure I'm doing something wrong.
UPDATE: The program builds and install at the desired location but when I try to run it like so: ./helloworld, I get: bash: ./helloworld: No such file or directory It has execution rights. What is the matter with it? (I try to run it after I mount the rootfs.ext2 into a ubuntu directory, the target arch for buildroot is i386, so it should be ok, right?)
After building and installing the HelloWorld program, and eventually running it, I'd like to add to init.d so it starts after booting, and replace the HelloWorld with a Qt Window that doesn't need a X server, like this thing here.
The main source of inspiration here.
Minimal tested example on top of 2016.05
GitHub upstream:
https://github.com/cirosantilli/buildroot/tree/in-tree-package-2016.05
This example adds the package source in-tree, which is simple for educational purposes and the way to go if you want to merge back (kudos!),
If you do not intend on merging back (booooh!), it is more likely that you will want to use Buildroot as a git submodule and either:
an out of tree package with BR2_EXTERNAL as shown at: https://github.com/cirosantilli/buildroot/tree/out-of-tree-2016.05
*_OVERRIDE_SRCDIR + other git submodules as explained at: How to modify the source of Buildroot packages for package development?
Files modified:
package/Config.in
menu "Misc"
source "package/hello/Config.in"
endmenu
package/hello/Config.in
config BR2_PACKAGE_HELLO
bool "hello"
help
Hello world package.
http://example.com
package/hello/hello.mk
################################################################################
#
# hello
#
################################################################################
HELLO_VERSION = 1.0
HELLO_SITE = ./package/hello/src
HELLO_SITE_METHOD = local
define HELLO_BUILD_CMDS
$(MAKE) CC="$(TARGET_CC)" LD="$(TARGET_LD)" -C $(#D)
endef
define HELLO_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(#D)/hello $(TARGET_DIR)/usr/bin
endef
$(eval $(generic-package))
package/hello/src/.gitignore
hello
package/hello/src/Makefile
CC = gcc
.PHONY: clean
hello: hello.c
$(CC) -o '$#' '$<'
clean:
rm hello
package/hello/src/hello.c
#include <stdio.h>
int main(void) {
puts("hello");
}
Usage:
make qemu_x86_64_defconfig
echo 'BR2_PACKAGE_HELLO=y' >> .config
make BR2_JLEVEL=2
qemu-system-x86_64 -M pc -kernel output/images/bzImage -drive file=output/images/rootfs.ext2,if=virtio,format=raw -append root=/dev/vda -net nic,model=virtio -net user
From inside qemu:
hello
Expected output:
hello
Tested in Ubuntu 16.04.
In general, the sources for buildroot packages are taken from a (downloaded) tarball. What you are doing right now (placing the sources inside package/HelloWorld) is not the right way to proceed.
Buildroot does have provisions for 'local' package sources, which you could use if you really need to. You'll need the HELLOWORLD_SITE_METHOD variable for that.
Please refer to http://buildroot.uclibc.org/downloads/manual/manual.html#adding-packages for more information.
Also, you don't need to define HELLOWORLD_DIR, HELLOWORLD_BINARY, HELLOWORLD_TARGET_BINARY.
Update: regarding your additional question:
UPDATE: The program builds and install at the desired location but when I try to run it
like so: ./helloworld, I get: bash: ./helloworld: No such file or directory, it has
execution rights.. what is the matter with it? (I try to run it after I mount the
rootfs.ext2 into a ubuntu directory, the target arch for buildroot is i368, so it should
be ok, right?)
No, it does not work like that. You can't just mount rootfs.ext2 and expect to run programs from it. This is, among others, because the programs inside rootfs.ext2 are compiled against the libraries also inside rootfs.ext2, but if you run it like that it will use the libraries in /usr/lib. You either have to boot your system entirely with the rootfs.ext2, use qemu, or use a chroot environment. For chroot, you should use the 'tar' filesystem format, not ext2. See also here:
http://buildroot.uclibc.org/downloads/manual/manual.html#_chroot

Command line Arduino compiling and uploading?

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".

Resources