I've got a Stellaris Launchpad board with a Cortex M4F on it. I want to use FreeRTOS on the board with some of my own C++ code. FreeRTOS, however, is written in C so will not compile with G++; I've tried.
I read somewhere that I should compile FreeRTOS with gcc, then compile my application code with g++, then pull them together using the linker. This makes sense, but I'm really struggling with how to put this behaviour down in a Makefile. I found this Makefile which just confused me more.
Currently, I'm just using the Makefile distributed with the FreeRTOS example in the Stellaris demos, but that's set up for C code only. This question is asking something similar to what I'm after, but I can't wrap my head around how to compile FreeRTOS with GCC and the rest of my code with G++.
FreeRTOS apparently wraps it's code in extern "C" { } directives but attempting using G++ still fails when compiling the FreeRTOS codebase.
I don't like posting large amounts of code on SO, but the more information the better I suppose. The Stellaris demos have a common makedefs file:
# Get the operating system name. If this is Cygwin, the .d files will be
# munged to convert c: into /cygdrive/c so that "make" will be happy with the
# auto-generated dependencies.
os:=${shell uname -s}
# The compiler to be used.
ifndef COMPILER
COMPILER=gcc
endif
# Definitions for using GCC.
ifeq (${COMPILER}, g++)
# Get the prefix for the tools to use. Use arm-stellaris-eabi if it exists,
# otherwise fall back to arm-none-eabi.
PREFIX=${shell type arm-stellaris-eabi-gcc > /dev/null 2>&1 && \
echo arm-stellaris-eabi || echo arm-none-eabi}
# The command for calling the compiler.
CC=${PREFIX}-${COMPILER}
# The location of the C compiler
# ARMGCC_ROOT is used by some makefiles that need to know where the compiler
# is installed. It is not used further for normal stellarisware apps
ARMGCC_ROOT:=${shell dirname '${shell sh -c "which ${CC}"}'}/..
# Determine the compiler CPU/FPU options based on the processor variant.
ifndef VARIANT
CPU=-mcpu=cortex-m3
FPU=
else
ifeq (${VARIANT}, cm3)
CPU=-mcpu=cortex-m3
FPU=
else
ifeq (${VARIANT}, cm4f)
CPU=-mcpu=cortex-m4
FPU=-mfpu=fpv4-sp-d16 -mfloat-abi=softfp
else
$(error Unknown processor variant ${VARIANT}!)
endif
endif
endif
# The flags passed to the assembler.
AFLAGS=-mthumb \
${CPU} \
${FPU} \
-MD
# The flags passed to the compiler.
CFLAGS=-mthumb \
${CPU} \
${FPU} \
-Os \
-ffunction-sections \
-fdata-sections \
-MD \
-Wall \
-pedantic \
-DPART_${PART} \
-c
# The command for calling the library archiver.
AR=${PREFIX}-ar
# The command for calling the linker.
LD=${PREFIX}-ld
# The flags passed to the linker.
LDFLAGS=--gc-sections
# Get the location of libgcc.a from the GCC front-end.
LIBGCC=${shell ${CC} ${CFLAGS} -print-libgcc-file-name}
# Get the location of libc.a from the GCC front-end.
LIBC=${shell ${CC} ${CFLAGS} -print-file-name=libc.a}
# Get the location of libm.a from the GCC front-end.
LIBM=${shell ${CC} ${CFLAGS} -print-file-name=libm.a}
# The command for extracting images from the linked executables.
OBJCOPY=${PREFIX}-objcopy
# Tell the compiler to include debugging information if the DEBUG environment
# variable is set.
ifdef DEBUG
CFLAGS+=-g -D DEBUG
endif
# Add the tool specific CFLAGS.
CFLAGS+=${CFLAGSgcc}
# Add the include file paths to AFLAGS and CFLAGS.
AFLAGS+=${patsubst %,-I%,${subst :, ,${IPATH}}}
CFLAGS+=${patsubst %,-I%,${subst :, ,${IPATH}}}
# The rule for building the object file from each C source file.
${COMPILER}${SUFFIX}/%.o: %.c
#if [ 'x${VERBOSE}' = x ]; \
then \
echo " CC ${<}"; \
else \
echo ${CC} ${CFLAGS} -D${COMPILER} -o ${#} ${<}; \
fi
#${CC} ${CFLAGS} -D${COMPILER} -o ${#} ${<}
ifneq ($(findstring CYGWIN, ${os}), )
#sed -i -r 's/ ([A-Za-z]):/ \/cygdrive\/\1/g' ${#:.o=.d}
endif
# The rule for building the object file from each assembly source file.
${COMPILER}${SUFFIX}/%.o: %.S
#if [ 'x${VERBOSE}' = x ]; \
then \
echo " AS ${<}"; \
else \
echo ${CC} ${AFLAGS} -D${COMPILER} -o ${#} -c ${<}; \
fi
#${CC} ${AFLAGS} -D${COMPILER} -o ${#} -c ${<}
ifneq ($(findstring CYGWIN, ${os}), )
#sed -i -r 's/ ([A-Za-z]):/ \/cygdrive\/\1/g' ${#:.o=.d}
endif
# The rule for creating an object library.
${COMPILER}${SUFFIX}/%.a:
#if [ 'x${VERBOSE}' = x ]; \
then \
echo " AR ${#}"; \
else \
echo ${AR} -cr ${#} ${^}; \
fi
#${AR} -cr ${#} ${^}
# The rule for linking the application.
${COMPILER}${SUFFIX}/%.axf:
#if [ 'x${SCATTERgcc_${notdir ${#:.axf=}}}' = x ]; \
then \
ldname="${ROOT}/${COMPILER}/standalone.ld"; \
else \
ldname="${SCATTERgcc_${notdir ${#:.axf=}}}"; \
fi; \
if [ 'x${VERBOSE}' = x ]; \
then \
echo " LD ${#} ${LNK_SCP}"; \
else \
echo ${LD} -T $${ldname} \
--entry ${ENTRY_${notdir ${#:.axf=}}} \
${LDFLAGSgcc_${notdir ${#:.axf=}}} \
${LDFLAGS} -o ${#} $(filter %.o %.a, ${^}) \
'${LIBM}' '${LIBC}' '${LIBGCC}'; \
fi; \
${LD} -T $${ldname} \
--entry ${ENTRY_${notdir ${#:.axf=}}} \
${LDFLAGSgcc_${notdir ${#:.axf=}}} \
${LDFLAGS} -o ${#} $(filter %.o %.a, ${^}) \
'${LIBM}' '${LIBC}' '${LIBGCC}'
#${OBJCOPY} -O binary ${#} ${#:.axf=.bin}
endif
The above file is included by the Makefile itself (below):
# Defines the part type that this project uses.
PART=LM4F120H5QR
# Set the processor variant.
VARIANT=cm4f
# The base directory for StellarisWare.
ROOT=../lib
COMPILER=gcc
# Include the common make definitions.
include ${ROOT}/makedefs
# Where to find source files that do not live in this directory.
VPATH=${ROOT}/FreeRTOS/Source/portable/GCC/ARM_CM4F
VPATH+=${ROOT}/FreeRTOS/Source/portable/MemMang/
VPATH+=${ROOT}/FreeRTOS/Source
VPATH+=${ROOT}/drivers
VPATH+=${ROOT}/utils
# Where to find header files that do not live in the source directory.
IPATH=.
IPATH+=..
IPATH+=${ROOT}
IPATH+=${ROOT}/FreeRTOS/Source/portable/GCC/ARM_CM4F
IPATH+=${ROOT}/FreeRTOS
IPATH+=${ROOT}/FreeRTOS/Source/include
IPATH+=${ROOT}
# The default rule, which causes the FreeRTOS example to be built.
all: ${COMPILER}
all: ${COMPILER}/freertos_demo.axf
# The rule to clean out all the build products.
clean:
#rm -rf ${COMPILER} ${wildcard *~}
# The rule to create the target directory.
${COMPILER}:
#mkdir -p ${COMPILER}
# Rules for building the FreeRTOS example.
${COMPILER}/freertos_demo.axf: ${COMPILER}/buttons.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/freertos_demo.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/heap_2.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/led_task.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/list.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/port.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/queue.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/rgb.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/startup_${COMPILER}.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/switch_task.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/tasks.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/uartstdio.o
${COMPILER}/freertos_demo.axf: ${COMPILER}/ustdlib.o
${COMPILER}/freertos_demo.axf: ${ROOT}/driverlib/${COMPILER}-cm4f/libdriver-cm4f.a
${COMPILER}/freertos_demo.axf: freertos_demo.ld
SCATTERgcc_freertos_demo=freertos_demo.ld
ENTRY_freertos_demo=ResetISR
CFLAGSgcc=-DTARGET_IS_BLIZZARD_RA1
# Include the automatically generated dependency files.
ifneq (${MAKECMDGOALS},clean)
-include ${wildcard ${COMPILER}/*.d} __dummy__
endif
Some of my directory structure is as follows:
Projects/
lib/
FreeRTOS/
driverlib/
drivers/
inc/
utils/
makedefs
TestProject/
loads.cpp
of.cpp
files.h
here.h
Makefile
If I'm correct in saying that FreeRTOS must be compiled with GCC, then linked with my C++ project code, how can I modify my current Makefile to do that? I want a reasonably generic solution so I can re-use it in other projects, but I don't know much about the C/C++ build process or Makefiles, hence me asking this (lengthy) question. I don't want/mean to sound like I'm asking a "do this for me" question, but I really cannot work out how to do this despite searching on Google and on SO.
I don't use FreeRTOS with C++ myself, but it has been discussed many times on the FreeRTOS forum and there are a few C++ frameworks in the FreeRTOS Interactive site.
Related
I'm attempting to integrate an L2CAP server (in C - uses BlueKitchen's btstack) with a UDP server (in C++). To start, I've attempted to just add the code from the L2CAP server into the "main.cpp" file of the UDP server. I included all of the relevant C libraries and headers using extern "C" {...}. At first, I'd get errors on the include statements for the btstack files. I solved this by modifying the make file to include "INC = -I./directory/...". Next, I dealt with problems the g++ compiler found with the pasted C code (ex. adding spaces between literals and strings). After resolving those, it seems that none of the bstack files/functions are being linked properly as this is what I get when I attempt to "make":
"undefined reference to 'every single btstack function call in main.cpp'
My makefile. Note that a lot of this is probably unnecessary/does nothing. I was just trying anything and everything and borrowing lines from the btstack port makefile and seeing if they'd work.
CORE += \
btstack_chipset_bcm.c \
btstack_chipset_bcm_download_firmware.c \
btstack_control_raspi.c \
btstack_link_key_db_tlv.c \
btstack_run_loop_posix.c \
btstack_tlv_posix.c \
btstack_uart_posix.c \
btstack_slip.c \
hci_dump_posix_fs.c \
hci_transport_h4.c \
hci_transport_h5.c \
le_device_db_tlv.c \
main.c \
wav_util.c \
btstack_stdin_posix.c \
raspi_get_model.c \
rijndael.c
.INCLUDE : home/pi/udpDemo/inc/btstack-master/example/Makefile.inc
CC=g++
CFLAGS=-Wall -Wextra -pedantic -std=c++11
SRC=$(wildcard ./src/*.cpp)
OBJ=$(patsubst ./src/%.cpp, ./obj/%.o, $(SRC))
INC=-I./inc \
-I./inc/btsrc \
-I./inc/btsrc/ble \
-I./inc/btsrc/ble/gatt-service \
-I./inc/platform/embedded \
-I./inc/platform/posix \
-I./inc/chipset/bcm \
-I./inc/3rd-party/tinydir \
-I./inc/3rd-party/rijndael \
-I./inc/port/raspi \
-I./src
LDFLAGS += -lrt
VPATH += src
VPATH += inc/3rd-party/rijndael
VPATH += inc
VPATH += inc/btsrc \
VPATH += inc/btsrc/ble \
VPATH += inc/btsrc/ble/gatt-service \
VPATH += inc/platform/embedded \
VPATH += inc/platform/posix \
VPATH += inc/chipset/bcm \
VPATH += inc/3rd-party/tinydir \
VPATH += inc/3rd-party/rijndael \
VPATH += inc/port/raspi \
LIBS=
TARGET=test
bindir=/usr/local/bin
$(TARGET):$(OBJ)
$(CC) -o $# $^ $(CFLAGS)
$(OBJ):./obj/%.o:./src/%.cpp
$(CC) $(CFLAGS) -c $^ -o $# -I$(INC)
clean:
rm -rf $(TARGET) $(OBJ)
install:$(TARGET)
install -g root -o root $(TARGET) $(bindir)/$(TARGET)
uninstall:$(bindir)/$(TARGET)
rm $(bindir)/$(TARGET)
It looks like there are both makefile issues and compile issues here. Solving both at the same time is hard. Below is a simplified and commented (but untested) version of your makefile that might be a good starting point for you.
Your original makefile looks like it was including a lot of stuff from the btstack build system. It's usually not a good idea to mesh two separate projects together like that, both for technical and licensing reasons. The typical way to use third-party code is to compile that code into a library and then have your code link against that library. You'll have to consult the documentation for btstack for details on how to do that, I'm not familiar with that particular library.
# Which compiler to use
CC=g++
# Options to pass to the compiler
CFLAGS=-Wall -Wextra -pedantic -std=c++11
# Options to pass to the linker
LDFLAGS=-Wall -Wextra
LDFLAGS+=-lbtstack # Link with 'libbtstack.a'
LDFLAGS+=-L/path/to/btstack # Where to find the btstack libraries that were built separately
# Source files to compile (everything in 'src' directory)
SRC=$(wildcard src/*.cpp)
# Convert names of source files into their corresponding object files
OBJ=$(patsubst src/%.cpp, obj/%.o, $(SRC))
# Directories where headers are kept
INC=-Isrc
INC+=-I/path/to/btstack/headers
# Name of the program
TARGET=test
# Rule for linking the .o files together to build the program
$(TARGET): $(OBJ)
$(CC) $(LDFLAGS) -o $# $^
# Rule for making a .o file from a .cpp file
obj/%.o: src/%.cpp
$(CC) $(CFLAGS) -c $^ -o $# -I$(INC)
# Rule for deleting output and temporary files
clean:
rm -rf $(TARGET) $(OBJ)
This will compile all the .cpp files in your src directory and link them with libbtstack.a to create a program named test. After you build the btstack library, update the LDFLAGS and INC variables with the actual paths to the btstack library and headers, respectively.
I have a rather large C program that I have already written. I'm now being asked to utilize a C++ class that a co-worker has written. I'm use to working with python, so writing my application in C and now being asked to work with C++ is causing some migraines. So ignoring my main application I decided to do some research and came across a youtube video that shows me how to do a very simple C program that calls a C++ class.
In order to compile the C program and allow it to call a C++ file, I needed to do two things, 1) use the C++ compiler (g++) and make sure to surround my c++ functions with < extern "C">. By doing this I was able to compile and run the application with no issues.
Here are the files that I'm currently using.
cppObject.cpp
cppObject.h
cppFunctions.cpp
cppFunctions.h
test.c
"test.c" is where the main method is, which calls the cppFunctions class, which then references functions within cppObject.cpp. Now I don't think I need to go into each of these functions as I can compile this with no issues, using.
g++ cppObject.cpp cppFunctions.cpp test.c -o test_exc
This generates an executable which runs with no issues.
Now because this is being built with Petalinux, Petalinux generates a recipe-app that includes a bitbake file and a makefile. Which both need to be modified in some way to accomplish my goal.
I'll be using this test case to reference for my main application.
As my C application has mainly been written, compiles, and runs with no issues. I decided to model the makefile and bitbake files after them.
APP = APP_name
# Add any other object files to this list below
APP_OBJS = file1.o \
file2.o \
file3.o \
file4.o \
file5.o \
# ...
all: build
build: $(APP)
LDLIBS += -lm
LDFLAGS += -lpthread
$(APP): $(APP_OBJS)
$(CC) -o $# $(APP_OBJS) $(LDFLAGS) $(LDLIBS)
clean:
rm -f $(APP) *.o
So based on the above makefile I attempted the same thing, using the test applications file names, and g++ instead of gcc
APP = test
# Add any other object files to this list below
APP_OBJS = cppObject.o cppFunctions.o test.o
all: build
build: $(APP)
$(APP): $(APP_OBJS)
$(CXX) -o $# $(APP_OBJS) $(LDFLAGS) $(LDLIBS)
clean:
rm -f $(APP) *.o
Now the bitbake file which matches my original application looks like this.
#
# This file is the **** recipe.
#
SUMMARY = "Simple **** application"
SECTION = "PETALINUX/apps"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://file1.c \
file://file2.c \
file://file3.c \
file://file4.c \
file://file5.c \
file://file2.h \
file://file3.h \
...
"
S = "${WORKDIR}"
do_compile() {
oe_runmake
}
do_install() {
install -d ${D}${bindir}
install -m 0755 **** ${D}${bindir}
}
I ended up making this one for the test application
#
# This file is the test recipe.
#
SUMMARY = "Simple test application"
SECTION = "PETALINUX/apps"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://cppObject.cpp \
file://cppFunctions.cpp \
file://cppObject.h \
file://cppFunctions.cpp \
file://test.c \
file://Makefile \
"
S = "${WORKDIR}"
do_compile() {
oe_runmake
}
do_install() {
install -d ${D}${bindir}
install -m 0755 test ${D}${bindir}
}
The petalinux-build -c for the application fails to build and the main error "test.c:2:10: fatal error: cppFunctions.h No such file or directory"
If I setup the makefile on its own and run make, it will build just fine, if I replace the objectfiles with the C/C++ files instead.
I'm assuming what is happening is Petalinux uses the bitbake file to generate the object files. Which then the Makefile uses to build the actual application.
Any insight that would allow me to use petalinux to build the application.
So caught a error in the .bb file, #vermaete also pointed it out. I left off the cppFunctions.h file. I ended up adding it to the .bb file and rebuilt the recipe. Unfortunately, I'm still getting a build error. However, its different, in that its having issues with an undefined reference.
undefined reference to 'printObjValue'
Which is a function call.
I have several very long compilation lines, and I want to make them a little more automatized and easier to use, by creating a script. I have found that makefile should be good for this purpose, however I am struggling with the file format.
My compilation line looks something like this:
g++ -std=c++11 -O3 -DNDEBUG \
-I /Users/whizzil/Desktop/proj/include \
-L /Users/whizzil/Desktop/proj/lib \
main.cpp \
-o program \
-lsdsl -ldivsufsort -ldivsufsort64 -Wno-inconsistent-missing-override
So I have several compiler flags, then include and lib parts, then linker options, and then ignore warnings flag.
I tried to write a makefile like this:
# what compiler to use
CC=g++
# options to the compiler
CFLAGS=-std=c++11 -03 -DNDEBUG
# include header files
INCLUDE=-I /Users/whizzil/Desktop/proj/include
# source lib files
LIB=-L /Users/whizzil/Desktop/proj/lib
# sources
SOURCES=main.cpp
#executable
EXECUTABLE=main
But I am not sure how to proceed. Could anyone help me out with the example makefile for this compile line, so I understand the concept?
Start with something simple and straightforward that works:
program:
g++ -std=c++11 -O3 -DNDEBUG \
-I /Users/whizzil/Desktop/proj/include \
-L /Users/whizzil/Desktop/proj/lib \
main.cpp \
-o program \
-lsdsl -ldivsufsort -ldivsufsort64 -Wno-inconsistent-missing-override
Then introduce a variable or two:
# what compiler to use
CC=g++
# options to the compiler
CFLAGS=-std=c++11 -03 -DNDEBUG
program:
$(CC) $(CFLAGS) \
-I /Users/whizzil/Desktop/proj/include \
-L /Users/whizzil/Desktop/proj/lib \
main.cpp \
-o program \
-lsdsl -ldivsufsort -ldivsufsort64 -Wno-inconsistent-missing-override
Then a few more:
# what compiler to use
CC=g++
# options to the compiler
CFLAGS=-std=c++11 -03 -DNDEBUG
# include header files
INCLUDE=-I /Users/whizzil/Desktop/proj/include
# source lib files
LIB=-L /Users/whizzil/Desktop/proj/lib
program:
$(CC) $(CFLAGS) $(INCLUDE) $(LIB) \
main.cpp \
-o program \
-lsdsl -ldivsufsort -ldivsufsort64 -Wno-inconsistent-missing-override
The variable LIB actually refers to a directory, so let's rename it LIBDIR and introduce LIBS:
# what compiler to use
CC=g++
# options to the compiler
CFLAGS=-std=c++11 -03 -DNDEBUG
# include header files
INCLUDE=-I /Users/whizzil/Desktop/proj/include
# source lib files
LIBDIR=-L /Users/whizzil/Desktop/proj/lib
LIBS = -lsdsl -ldivsufsort -ldivsufsort64
program:
$(CC) $(CFLAGS) $(INCLUDE) $(LIBDIR) main.cpp \
-o program $(LIBS) -Wno-inconsistent-missing-override
Further refinements are possible, once you have that much working.
I have a script which generates multiple C++ .h and .cpp files, based on a configuration file. This script also generates a file called 'Makefile.inc', and this file contains a variable with the required object filenames, for the generated .cpp files.
Example of a Makefile.inc file (all paths are absolute):
MESSAGE_OBJS = \
/scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/error-message.o \
/scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/challenge-request-message.o \
/scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/challenge-response-message.o \
/scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/login-message.o \
/scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/get-game-list-message.o \
/scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/game-list-response-message.o \
/scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/join-game-message.o \
/scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/connect-to-game-message.o \
/scratch/openttd/software/AtLargePlatform/branches/lucas/libatlarge/atlarge/messages/leave-game-message.o
Using the answer in this question as base, I created the following Makefile:
# Include the generated makefile for messages.
# This includes a variable with all message targets
include atlarge/messages/Makefile.inc
# Create a variable with all source targets
LIBOBJS = \
atlarge/exceptions.o \
atlarge/message-factory.o \
atlarge/envelope.o \
atlarge/client.o \
atlarge/user.o \
atlarge/atlarge-protocol.o \
atlarge/atlarge-gameserver.o \
$(MESSAGE_OBJS)
CXXFLAGS += -W -Wall -I. -g -O3 -MD \
`pkg-config jansson --cflags` \
`libgcrypt-config --cflags` \
`pkg-config glib-2.0 --cflags` \
-fPIC -DDEBUG -DENABLE_LOGGING
PREFIX = /usr/local
# TODO use pkg-config for jansson
LDLIBS += -lm -ljansson -latlarge-util `libgcrypt-config --libs` `pkg-config glib-2.0 --libs`
LDFLAGS += -shared -L/usr/local/lib
# Include automatically generated dependencies
-include $(LIBOBJS:.o=.d)
all: libatlarge.so
# If the message Makefile doesn't exist yet, generate it
atlarge/messages/Makefile.inc: atlarge/messages/messages.conf
python ../common/messagegen.py -o ./atlarge/messages/ atlarge/messages/messages.conf
libatlarge.so: $(LIBOBJS)
$(CXX) $(LDFLAGS) -o $# $^ $(LDLIBS)
clean:
#rm -f *.o
#rm -f atlarge/*.o
#rm -f atlarge/messages/*.o
#rm -f atlarge/messages/*.cpp
#rm -f atlarge/messages/*.h
#rm -f atlarge/messages/Makefile.inc
#rm -f atlarge/*.d
#rm -f atlarge/messages/*.d
#rm -f *.d
#rm -f ../common/*.d
#rm -f ../common/*.o
#rm -f *.a
#rm -f *.so
#rm -f tags
install: libatlarge.so
#install -m 0644 $^ $(PREFIX)/lib
#install -m 0755 -d $(PREFIX)/include/atlarge
#install -m 0755 -d $(PREFIX)/include/atlarge/messages
#install -m 0644 -D atlarge/*.h $(PREFIX)/include/atlarge
#install -m 0644 -D atlarge/messages/*.h $(PREFIX)/include/atlarge/messages
#ldconfig
#echo "Installed"
.PHONY: all clean install splint messages
As you can see, I first include the generated Makefile.inc. Then a variable with all library object files is defined, and this variable makes use of the variable declared in the generated Makefile.inc. After that some variables with compiler flags are declared.
To make use of Makefile remaking, I included a target rule for the generated Makefile.inc, so if the dependency of Makefile.inc (the configuration file) is newer than Makefile.inc, it gets regenerated, and Make will restart itself.
So this is the goal:
Check if Makefile.inc needs to be (re)generated.
Include it
Use the variable inside Makefile.inc in the $LIBOBJS variable in the main Makefile.
And this actually works. If I update the messages.conf file, Make detects that, and will run the python script. It will then restart itself, include the new Makefile.inc, and then proceed with compiling.
But here comes the part that doesn't work: if I don't update the messages.conf file, but only .h or .cpp files which are by default in the $LIBOBJS list, Make will not proceed to compile.
For example, if alter client.cpp and no other files, I get the following error:
make: `atlarge/exceptions.o' is up to date.
Well yeah, great you found out that exceptions.o is up to date, but I altered client.cpp, so why don't you start compiling that one? Why does make quit immediatly after seeing that the first target in LIBOBJS is up to date?
Who knows what's causing this, and what could be a solution? Is there maybe a better way to handle code generation with makefiles?
Thanks in advance.
NB: I also use dependency files generated by gcc, and that was working fine before I added the code generation, so I don't think that's a problem.
You need to move the all target to come BEFORE the include. Make always builds the first target it sees in the makefile unless you give a specific target on the command line. Since the include comes before any target, the first target defined in Makefile.inc will be the default target and when you run make that's the one that will be built. That's why it tries to build exceptions.o and then stops. If you run make all explicitly, it will work as you expect.
Where is the dependency for the object files on the source files
or the header files? There is an implicit rule which should
pick up the dependencies if the .cpp file is in the same
directory as the .o, but if they're not, you'll have to
provide your own, or use VPATH (see §4.5.1 in the manual). And
you also need to generate the dependencies for the includes, see
§4.1.4 in the manual.
I am trying to make a project using a library named BigInt. My file structure is:
/Users/wen/Projects/challenge/fibonacci3/fibonacci3.cpp
/Users/wen/Projects/challenge/fibonacci3/Makefile
/Users/wen/Projects/include/bigint/<.cc files and .hh files>
/Users/wen/Projects/include/bigint/Makefile
The Fibonacci3 Makefile is as of
LD_FLAGS =
CC_FLAGS =
# Include libraries
include /Users/wen/Projects/include/bigint/Makefile
# Build object files
%.o: %.cc %.cpp $(library-cpp)
g++ -c -o $# $(CC_FLAGS)
# Link object files
fibonacci3: fibonacci3.o $(library-objects)
g++ -o $# $(LD_FLAGS)
and the bigint Makefile is as of (shortened)
# Mention default target.
all:
# Implicit rule to compile C++ files. Modify to your taste.
%.o: %.cc
g++ -c -O2 -Wall -Wextra -pedantic $<
# Components of the library.
library-cpp = \
BigUnsigned.cc \
BigInteger.cc \
BigIntegerAlgorithms.cc \
BigUnsignedInABase.cc \
BigIntegerUtils.cc \
library-objects = \
BigUnsigned.o \
BigInteger.o \
BigIntegerAlgorithms.o \
BigUnsignedInABase.o \
BigIntegerUtils.o \
library-headers = \
NumberlikeArray.hh \
BigUnsigned.hh \
BigInteger.hh \
BigIntegerAlgorithms.hh \
BigUnsignedInABase.hh \
BigIntegerLibrary.hh \
however, make reports that it could not find a rule for a header file?
make: *** No rule to make target `NumberlikeArray.hh', needed by `BigUnsigned.o'. Stop.
[Finished in 0.0s with exit code 2]
What is happening here? Headers are supposed to be included, not compiled, so why is make asking for one?
Thanks in advance!
Solution:
Instead of including the makefile, compile the sources in my own makefile. It worked! Thanks again.
The make program expects all files to be in the current directory. Since you include the second makefile into the current makefile, all files in that are relative to the current directory as well. You have to make sure that the files in the included makefile contains the correct paths.
Make gives this error when it cannot find a dependency; it then tries to build that dependency, but knows no rule to make this header file.
You might have mistyped the header file's name.