Makefile arm linux gcc

Simple makefile for C/C++ targets used with arm-linux-gcc

I would like to cross-compile a simple program for ARM architecture using the arm-linux-gcc suite of compilers [arm-linux-gcc (Buildroot 2011.08) 4.3.6]. I’ve attempted to use a simple makefile for compiling C code, and another simple makefile for compiling C++ code. For example, my makefile for C code is reproduced below, but it does not create an ELF binary for running on my embedded system. The host system is x64 GNU Linux. Here is the listing of my very simple makefile for a C program:

CC=arm-linux-gcc CFLAGS=-Wall main: test.o clean: rm -f test test.o 

The makefile reproduced above only creates an object file with extension .o, and does not create an ELF binary. I’ve Googled for a good solution, but I can’t seem to find one webpage showing example cross-compile ARM makefiles for both C and C++ programs. Perhaps an answer to this post could show such examples.

2 Answers 2

Have a look at the GNU make manual ( info make ), Section 10.2. It has a catalogue of the implicit rules, i.e. the rules where you don’t need to explicitly state the commands. Like @GregHewgill thought, the «Linking a single object file» implicit rule builds N from N.o , but the name must match. Therefore, you can either name your executable like your object file, in which case

or (more standard because it defines the all target)

completely suffice. You can also write out the rule explicitly, like Greg Hewgill also described. In this case, the standard rule is:

 $(CC) $(LDFLAGS) N.o $(LOADLIBES) $(LDLIBS) 

Include the LDFLAGS and LDLIBS in your Makefile, it makes life easier for users.

(sic: I think LOADLIBES is really LOADLIBS, and the author missed the -o ).

Overall, I’d recommend autoconf and automake instead of hand-rolling makefiles. Gives you a bunch of Makefile features for very little work.

Источник

Writing a makefile for ARM project

This is a simple raspberry pi kernel that makes a LED blink! I currently use a simple bat file with the following content to build it:

arm-none-eabi-gcc -g -O0 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7 -nostartfiles -Wl,-T,linker.ld src/kernel.c src/boot.c src/boot.s -o build/kernel.elf arm-none-eabi-objcopy build/kernel.elf -O binary build/kernel7.img 
  • Before compilation, clean all *.elf and *.img files from the build directory.
  • Compile all *.c and *.s files from the src directory.
  • Output the kernel.elf file into the build directory.
  • Use the linker script linker.ld .
  • After compilation, run objcopy to generate a binary file.

1 Answer 1

A typical Makefile may look like. Wait there’s a documentation about GNU Make here with a nice simple Makefile: http://www.gnu.org/software/make/manual/make.html#Simple-Makefile

Читайте также:  Linux mint wine удаление

So for you a simple one to start may be:

SRC := $(wildcard src/*.c src/*.s) CFLAGS := -g -O0 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7 -nostartfiles -Wl,-T,linker.ld all: build/kernel.img build/kernel.elf: $(SRC) arm-none-eabi-gcc $(CFLAGS) $(SRC) -o $@ %.img: %.elf arm-none-eabi-objcopy $< -O binary $@ clean: rm -f build/*.elf build/*.img 

(Be carefull, recipes have to start with a tab, not four spaces like here, it's important for make to understand your file, so copying-pasting won't work.)

You don't actually need to remove elf and img files before compiling, that's the GNU Make role to know if it has to rebuild or not according to file modification times.

$ tree . ├── build ├── Makefile └── src ├── boot.c ├── boot.s └── kernel.c $ make arm-none-eabi-gcc -g -O0 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7 -nostartfiles -Wl,-T,linker.ld src/boot.c src/kernel.c src/boot.s -o build/kernel.elf arm-none-eabi-objcopy build/kernel.elf -O binary build/kernel.img $ tree . ├── build │ ├── kernel.elf │ └── kernel.img ├── Makefile └── src ├── boot.c ├── boot.s └── kernel.c $ make make: Nothing to be done for 'all'. $ touch src/boot.c # If I touch a file, make will have to rebuild evrything: $ make arm-none-eabi-gcc -g -O0 -mfpu=neon-vfpv4 -mfloat-abi=hard -march=armv7-a -mtune=cortex-a7 -nostartfiles -Wl,-T,linker.ld src/boot.c src/kernel.c src/boot.s -o build/kernel.elf arm-none-eabi-objcopy build/kernel.elf -O binary build/kernel.img 

Источник

Guide: Using make for ARM Cross-Development

Make is a tool that automates building programs; a Makefile describes the commands and options used in the build process. As you will see soon enough, using a Makefile saves you a lot of retyping and makes your life as a developer a whole lot smoother!

This guide introduces Makefiles using examples of cross-development for the ARM architecture. For further information about Makefiles in general, check out the other resources on the bottom of this page.

An example Makefile

The example makefile below builds the blink.bin program out of the blink.c source file. Our labs and assignments will include similar Makefiles, so you will soon become familiar with the common structure.

NAME = blink CFLAGS = -g -Wall -Og -std=c99 -ffreestanding LDFLAGS = -nostdlib all: $(NAME).bin %.bin: %.elf arm-none-eabi-objcopy $ -O binary $@ %.elf: %.o arm-none-eabi-gcc $(LDFLAGS) $ -o $@ %.o: %.c arm-none-eabi-gcc $(CFLAGS) -c $ -o $@ %.list: %.o arm-none-eabi-objdump -d $ > $@ run: $(NAME).bin rpi-run.py $ clean: rm -f *.o *.elf *.bin *.list 

This Makefile may look a bit cryptic at first! Let's try breaking it down step by step.

Rules and recipes

In lecture, Pat whipped up a simple doit script to automate retyping the commands to rebuild a program. The make tool is just a fancier version of doit. A Makefile is a text file that describes the steps needed to build a program. Here is an example of a very simple hard-coded Makefile containing three targets all , button.bin and clean :

all: button.bin button.bin: button.c arm-none-eabi-gcc -Og -g -Wall -std=c99 -ffreestanding -c button.c -o button.o arm-none-eabi-gcc -nostdlib button.o -o button.elf arm-none-eabi-objcopy button.elf -O binary button.bin clean: rm -f *.bin *.o 

Rules are written in the following way: "the dependencies on the right-hand-side are required to make the target on the left-hand-side." Thus the first line indicates that button.bin is required to make all . In other words, to make all , we must first make button.bin .

This brings us to the next rule for button.bin :

button.bin: button.c arm-none-eabi-gcc -Og -g -Wall -std=c99 -ffreestanding -c button.c -o button.o arm-none-eabi-gcc -nostdlib button.o -o button.elf arm-none-eabi-objcopy button.elf -O binary button.bin 

The ingredients (dependencies on the right-hand-side) are needed as the starting point to create the desired output (target on the left-hand-side). The indented lines that follow the rule are the commands that turn the ingredients into the final product. These steps are collectively called the recipe. Thus, in order to make button.bin , we start with our ingredient ( button.c ) and then step through the commands in the recipe.

We could add a comment to explain the additional flags included when invoking the compiler. Lines starting with # are treated as comments.

# Compiler flags used: # -std=c99 use the c99 standard # -Og generate optimized code designed for debugging # -g add debugging information # -Wall give warnings about *all* issues # -ffreestanding generate code assuming no operating system 

The final rule indicates what should happen when we make clean ; the recipe for the clean target removes any previous build products so the next compile starts fresh.

One particularly nifty thing make is that only rebuilds a target when one or more of the components it depends on has changed. If you attempt to re-build a target which is already up-to-date, make will tell you:

$ make make: Nothing to be done for `all'. 

Macros

After repeatedly copy-pasting the example Makefile to create a version for a new program, you can see the value in structuring it to be more general-purpose. After all, Makefiles are written for convenience!

NAME = blink CFLAGS = -std=c99 -Og -g -Wall -ffreestanding LDFLAGS = -nostdlib all: $(NAME).bin $(NAME).bin: $(NAME).c arm-none-eabi-gcc $(CFLAGS) -c $(NAME).c -o $(NAME).o arm-none-eabi-gcc $(LDFLAGS) $(NAME).o -o $(NAME).elf arm-none-eabi-objcopy $(NAME).elf -O binary $(NAME).bin clean: rm -f *.bin *.o 

We've added three macros up top. They're similar to variables in that they replace instances of the macro throughout the file with their assigned text. The $(macro_name) syntax is used to access the value of the macro. This makes it easy to change the name for a new program.

Pattern rules

We can further generalize our Makefile by using pattern rules that can be used to operate on any source file, without hard-coding to a particular name.

# This pattern rule compiles a C program into an object file. # filename.o is built from filename.c %.o: %.c arm-none-eabi-gcc $(CFLAGS) -c $ -o $@ # This pattern rule converts assembly instructions into an object file. # filename.o is built from filename.s %.o: %.s arm-none-eabi-as $(CFLAGS) $ -o $@ # This pattern rule links an object file into an executable ELF file. # filename.elf is built from filename.o %.elf: %.o arm-none-eabi-gcc $(LDFLAGS) $ -o $@ # This pattern rule extract binary from an ELF executable # filename.bin is built from filename.elf %.bin: %.elf arm-none-eabi-objcopy $ -O binary $@ 

The symbols that begin with $ and % in a pattern rule are handled by make using the following interpretations:

  • % is a wildcard symbol when used in a rule; %.o for example matches any file that ends with .o
  • $@ refers to the left part of the rule, before the :
  • $ < refers to the first element in the right part of the rule, after the :

One more special variable $^ refers to all elements in the right part of the rule, after the : , which is to say all of the dependencies.

For further convenience, we can add a rule for the run target. We use this target to invoke the command rpi-run.py blink.bin to load our newly-built program on the Pi.

# The run target uploads a freshly made binary image to rpi bootloader run: $(NAME).bin rpi-run.py $ 

With that finishing touch, you have a general Makefile that can be easily re-purposed for any Raspberry Pi project. Now that you know that a Makefile is just a cookbook that culminates in the tasty program you wish to create, you're ready to add your favorite recipes and bon appetit!

Going further

Some follow up references on Makefiles:

  • a Makefile tutorial
  • another Makefile tutorial
  • CS107 Guide to Makefiles
  • An inexhaustible source of make wisdom is the full manual for GNU make which will tell you more that you could ever want to know.
  • Reading makefiles from real world projects is a good way to see make in action. A search for makefile on github.com will turn up a treasure trove.

Q. Make is failing with a cryptic error about Makefile: *** missing separator . What gives?

A. In what is widely considered one of the dumber decisions in the history of computing, a Makefile distinguishes between tabs and spaces. The recipe lines for a target must begin with a tab and an equivalent number of spaces just won't do. Edit your makefile and replace those errant spaces with a tab to restore Makefile joy.

CS107e Winter 2023 · Site generated 2023-03-18 17:53

Источник

Оцените статью
Adblock
detector