10

I'm working on some bare-metal embedded code that runs on ARM, and thus has to deal with the whole ARM vs. THUMB mode distinction. The current build system uses static pattern rules to determine whether to compile files in ARM or THUMB mode.

$(ACOBJS) : %.o : %.c
    @echo
    $(CC) -c $(CFLAGS) $(AOPT) -I . $(IINCDIR) $< -o $@
$(TCOBJS) : %.o : %.c
    @echo
    $(CC) -c $(CFLAGS) $(TOPT) -I . $(IINCDIR) $< -o $@

Where ACOBJS is a list of output objects that should be in ARM mode and the same for TCOBJS and Thumb mode. These lists are created from the list of sources in the usual manner of

ACOBJS   = $(ACSRC:.c=.o)
TCOBJS   = $(TCSRC:.c=.o)

Currently this results in the object files from the build being strewn about the source tree, which I don't particularly desire. I've been trying to set this up for out of tree builds but haven't been able to get this to work. I don't necessarily need to get full out of tree builds working, but I would like to at least be able to use an output directory under which all the intermediate files end up going. What is the best strategy to achieve this under these constraints?

One option I'm considering is using either automake or the whole autotools toolchain to build a makefile. This would seem to support creating the type of makefile I want, but seems like overkill. It also seems like there would be an inherent impedance mismatch between autotools, which is designed for portable builds, and bare-metal embedded systems, where things like host tuple are dictated by the target micro.

megabytephreak
  • 588
  • 7
  • 17
  • Do you want all of the object files, executables and libraries to go into the same output directory? – Beta Feb 06 '11 at 06:19
  • Having everything end up in the same directory is OK, although not the best case. I currently have this working by replacing the static pattern rules with a target specific addition of the appropriate flags to CFLAGS. https://github.com/MegabytePhreak/power_supply/blob/master/rules.mk shows how I am currently doing things. – megabytephreak Feb 09 '11 at 01:39

3 Answers3

4

This is a bit old but I was just trying to do the same thing this was the first google hit. I thought it was worth sharing another approach since neither answer is convenient if you're not using autotools and want to be able to build in any directory with a single command and later just blow away that directory.

Here's an example of a Makefile that refers to files relative to the directory containing the Makefile.

MAKEFILE_DIR := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST))))
MFD := $(MAKEFILE_DIR)

CXX=g++
CXXFLAGS=-std=c++14 -Wall -Wextra -pedantic -c

test: test.o adjacency_pointers_graph.o
    $(CXX) $^ -o $@

%.o: $(MFD)/%.cpp $(MFD)/adjacency_pointers_graph.h
    $(CXX) $(CXXFLAGS) $< -o $@

Then to do an sort of source build:

mkdir build
cd build
make -f ../Makefile
Praxeolitic
  • 22,455
  • 16
  • 75
  • 126
  • `lastword` returns last element from list, so this will not work properly with generated .d (dependency) files placed in some obj subdir, or any other files included from dir(s) other than that one with Makefile. To fix it, use `firstword` instead of `lastword` in 1st line. – Daniel Frużyński Dec 20 '21 at 13:29
3

Considering/assuming you don't care about portability and are using GNU make, you can use the VPATH feature:

  • Create the directory where you want to do your build.
  • Create a 'Makefile' in that directory with (approximately) the following contents:

    path_to_source = ..
    VPATH = $(path_to_source)
    include $(path_to_source)/Makefile
  • Change the path_to_source variable to point to the root of your source tree.

Additionally you probably need to tweak your original Makefile to make sure that it supports the out of source build. For example, you can't reference to prerequisites from your build rules and instead must use $^ and $<. (See GNU make - Writing Recipes with Directory Search) You might also need to modify the vpath-makefile. For example: adding CFLAGS+=-I$(path_to_source) might be useful.

Also note that if a file is in both your source and build directory, make will use the file in your build directory.

bcmpinc
  • 3,202
  • 29
  • 36
1

On automake

If you use automake, you're pretty much using the entire autotools. automake cannot work without autoconf.

The Makefiles generated by automake support out-of-source builds and cross-compilation, so you should be able to create subdirectories arm/ and thumb/ and run ../configure --host=arm-host-prefix in arm/ and run ../configure --host=thumb-host-prefix in thumb/. (I don't know the actual host tuples that you'd use for each compiler.)

Using GNU make

Since you're using GNUMake, you could do something like this:

ACOBJS := $(addprefix arm/,$(ACSRC:.c=.o))
TCOBJS := $(addprefix thumb/,$(TCSRC:.c=.o))

Use something like this answer to ensure that the arm/ and thumb/ directories (and any subdirectories) exist.

Community
  • 1
  • 1
Jack Kelly
  • 18,264
  • 2
  • 56
  • 81
  • 1
    For ARM vs THUMB output, the same compiler is used, in this case, the host tuple is arm-none-eabi. In order con control which type of code is generated the flag -mthumb is used. – megabytephreak Feb 09 '11 at 01:35
  • 1
    Then if you use `automake`, you'd do something like `../configure --host=arm-none-eabi CFLAGS='-mthumb'`. Add other CFLAGS for optimisation &c. like normal. – Jack Kelly Feb 09 '11 at 02:40
  • 1
    @Jack: Wouldn't you rather do `../configure --host=arm-none-eabi` and then `libfoo_la_CFLAGS += -mthumb` for a convenience library of thumb code and `libbar_la_CFLAGS += ...` for a convenience lib of native ARM code? Globally setting `CFLAGS=-mthumb` would force all code to be compiled as thumb code, after all. – ndim Feb 14 '11 at 02:31
  • @ndim: depends on the details of the build. I don't know the details of arm cross-compilation well enough to say, but you make a good point. My thought was you'd have two separate out-of-tree builds: one for arm code and one for thumb code. – Jack Kelly Feb 14 '11 at 03:03
  • I would actually prefer libtool-less linking (`libfoo_a_CFLAGS`) for bare-metal code on embedded systems, as direct usage of `ld` allows more direct influence on linker scripts and memory layout. – ndim Feb 16 '11 at 01:58
  • Then if you don't need shared libraries, don't use libtool: `noinst_LIBRARIES = libfoo.a`, `libfoo_a_SOURCES = ...`, `bin_PROGRAMS = bar`, `bar_LDADD = libfoo.a`. Remember to add `AC_PROG_RANLIB` to `configure.ac`. – Jack Kelly Feb 16 '11 at 04:08