I need to add my own package to the openwrt image. On the wiki of the project I found this article.
I tried to follow the instructions for it, but in the end I did not manage to add my own package to the source code tree (the build ignored its presence).
Because of this, I tried to find some other way. And it turned out to be a this instruction. I followed the directions from there and compiled my own package.
But as you can see, the source code of that package does not depend on others and does not require any other build header files. Also, his Makefile completely includes instructions for compiling.
define Build/Compile
$(TARGET_CC) $(TARGET_CFLAGS) -o $(PKG_BUILD_DIR)/helloworld.o -c $(PKG_BUILD_DIR)/helloworld.c
$(TARGET_CC) $(TARGET_LDFLAGS) -o $(PKG_BUILD_DIR)/$1 $(PKG_BUILD_DIR)/helloworld.o
endef
But now this does not suit me, since another package that I want to add already has such dependencies.
I tried to bypass them like this (copy the source code to the build folder and call the makefile located there) but nothing came of it:
define Build/Prepare
echo $PKG_NAME
mkdir -p $(PKG_BUILD_DIR)
cp $(SOURCE_DIR)/* $(PKG_BUILD_DIR)
$(Build/Patch)
endef
define Build/Compile
$(PKG_BUILD_DIR) $(MAKE)
endef
I am getting next output:
$ make -C package/feeds/mypackages/helloworld compile TOPDIR=$PWD
make: Entering directory '/home/username/mypackages/examples/helloworld'
bash: mkhash: command not found
bash: mkhash: command not found
bash: mkhash: command not found
bash: mkhash: command not found
bash: mkhash: command not found
bash: mkhash: command not found
bash: mkhash: command not found
bash: mkhash: command not found
make: Nothing to be done for 'compile'.
make: Leaving directory '/home/username/mypackages/examples/helloworld'
My full Makefile for both package and binary:
include $(TOPDIR)/rules.mk
PKG_NAME:=helloworld
PKG_VERSION:=1.0
PKG_RELEASE:=1
SOURCE_DIR:=/home/username/helloworld
include $(INCLUDE_DIR)/package.mk
define Package/$(PKG_NAME)
SECTION:=utils
DEPENDS:= +libstdcpp
TITLE:=helloworld
endef
define Package/helloworld/description
A simple "Hello, world!" -application.
endef
define Build/Prepare
echo $PKG_NAME
mkdir -p $(PKG_BUILD_DIR)
cp $(SOURCE_DIR)/* $(PKG_BUILD_DIR)
$(Build/Patch)
endef
define Build/Compile
$(PKG_BUILD_DIR) $(MAKE)
endef
define Package/helloworld/install
# Install binary
#$(INSTALL_DIR) $(1)/usr/bin
#$(INSTALL_BIN) $(PKG_BUILD_DIR)/helloworld $(1)/usr/bin/
endef
$(eval $(call BuildPackage,$(PKG_NAME)))
,
TARGET = heloworld
OBJS = heloworld.o
CFLAGS += -Wall -Wextra
LDFLAGS += -lxsacpp -lxsac -lubus -lubox
CXXFLAGS += $(CFLAGS) -std=c++14
%.o : %.cpp
$(CXX) -c $(CXXFLAGS) $< -o $#
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) $(LDFLAGS) -o $# $^
clean:
rm *.o $(TARGET)
And actually my question is, what needs to be set in the Makefile to copy files correctly and call the local Makefile for package binary?
In order to copy files and directories you can use below step:
# copy all files and directories using **cp -r -f **
define Build/Prepare
echo $PKG_NAME
mkdir -p $(PKG_BUILD_DIR)
cp -r -f $(SOURCE_DIR)/* $(PKG_BUILD_DIR)
$(Build/Patch)
endef
In order to execute the local makefile use below step:
# Execute local makefile by giving path using '-C' option
define Build/Compile
`$(MAKE) -C $(PKG_BUILD_DIR)`
endef
Related
I've been provided the source code from an older project in c++ and need to compile and run it in a Docker container running Alpine Linux. I unfortunately don't have experience compiling in Linux or much with c++, with much google, I have tried to deploy a Docker container running Alpine Linux, install compile libraries/tools and try and compile using the make file, but I'm met with compile errors. I can't provide too much details about the source code as its company property, but I can provide the makefile and the steps I've been taking:
install compile tools in Alpine Linux:
apk update && apk add --no-cache autoconf build-base binutils cmake curl file gcc g++ git libgcc libtool linux-headers make musl-dev ninja tar unzip wget
makefile:
BIN := testExec
# relative paths to all project source files
SRCDIR := src
INCDIR := include
IDEDIR := ide_files
# files included in the tarball generated by 'make dist'
DISTFILES := $(BIN).a $(BIN).dll $(SRCDIR) $(INCDIR) $(IDEDIR)
# filename of the tar archive generated by 'make dist'
#DISTOUTPUT := $(BIN).tar.gz
# cross-compiler name prefix
CROSS := i686-pc-mingw32-
#CROSS := /usr/local/gnat-x86_64-darwin/bin/
# toolchain executables
CC := $(CROSS)gcc
CXX := $(CROSS)g++
LD := $(CROSS)gcc
AR := $(CROSS)ar
RM := rm
TAR := tar
PERL := perl
# path to script that generates ctags files
CTAGS := $(dir $(abspath $(lastword $(MAKEFILE_LIST))))ctags.pl
# output files generated by ctags
CTAGS_FILES := .tags .tags_sorted_by_file
# add other macro defines by calling make with a USER_DEFINES argument
# e.g. [ make USER_DEFINES='BLAH FOO="bar"' ] will add the string "-DBLAH -DFOO=bar" to your CFLAGS
UFLAGS := $(addprefix -D,$(USER_DEFINES))
DFLAGS := -DBUILD_DLL
# debugging + major profiling
#DBGFLAGS := -ggdb3 -feliminate-unused-debug-symbols -gno-strict-dwarf -pg -Q -ftime-report -fmem-report
# debugging + minor profiling
#DBGFLAGS := -ggdb3 -feliminate-unused-debug-symbols -gno-strict-dwarf -pg -Q
# debugging
DBGFLAGS := -ggdb3 -feliminate-unused-debug-symbols -gno-strict-dwarf
# ensure the profiling flags get included for the compiler -and- the linker
CFLAGS := $(DBGFLAGS) -Wall $(DFLAGS) $(UFLAGS) $(addprefix -I,$(INCDIR))
LDFLAGS := $(DBGFLAGS) -shared -lm
# flags required for dependency generation; passed to compilers
DEPFLAGS = -MT $# -MD -MP -MF $(DEPDIR)/$*.Td
COMPILE.c = $(CC) $(DEPFLAGS) $(CFLAGS) -c -o $#
LINK.o = $(LD) $(LDFLAGS) $(LDLIBS) -o $#.dll -Wl,--out-implib,$#.a
PRECOMPILE =
POSTCOMPILE = mv -f $(DEPDIR)/$*.Td $(DEPDIR)/$*.d
# source files
SRCS := $(wildcard $(SRCDIR)/*.c)
# intermediate directory for generated object files
OBJDIR := .o
# intermediate directory for generated dependency files
DEPDIR := .d
# object files, auto generated from source files
OBJS := $(patsubst %,$(OBJDIR)/%.o,$(basename $(SRCS)))
# dependency files, auto generated from source files
DEPS := $(patsubst %,$(DEPDIR)/%.d,$(basename $(SRCS)))
# compilers (at least gcc and clang) don't create the subdirectories automatically
$(shell mkdir -p $(dir $(OBJS)) >/dev/null)
$(shell mkdir -p $(dir $(DEPS)) >/dev/null)
.PHONY: all
all: $(BIN)
.PHONY: tar
tar: $(DISTFILES)
$(TAR) -czpvf $(DISTOUTPUT) --transform='s|^|$(BIN)/|' $^
.PHONY: dist
dist: $(BIN) tar
.PHONY: clean
clean:
$(RM) -rf $(OBJDIR) $(DEPDIR) $(BIN).a $(BIN).dll
.PHONY: distclean
distclean: clean
$(RM) -f $(DISTOUTPUT)
.PHONY: ctags
ctags:
$(PERL) $(GEN_CTAGS) $(dir $(SRCDIR))
.PHONY: check
check:
#echo no tests configured
.PHONY: help
help:
#echo ""
#echo " available make targets:"
#echo " all - [DEFAULT TARGET] compiles and links all files"
#echo " dist - creates a tarball containing sources and executables"
#echo " clean - removes executables and object file directories"
#echo " distclean - same as clean and also removes dist tarball"
#echo " ctags - creates ctags index files for entire project"
#echo " check - performs verification on project (not implemented)"
#echo ""
#echo " NOTE:"
#echo " you can pass additional flags to the compiler using the USER_DEFINES"
#echo " argument given to make, e.g. [ make USER_DEFINES='BLAH FOO=\"bar\"' ]"
#echo " will add the string \"-DBLAH -DFOO=bar\" to your CFLAGS"
.PHONY: $(BIN)
$(BIN): $(OBJS)
$(LINK.o) $^
$(OBJDIR)/%.o: %.c
$(OBJDIR)/%.o: %.c $(DEPDIR)/%.d
$(PRECOMPILE)
$(COMPILE.c) $<
$(POSTCOMPILE)
.PRECIOUS = $(DEPDIR)/%.d
$(DEPDIR)/%.d: ;
-include $(DEPS)
The makefile references i686-pc-mingw32-gcc so I've attempted to install the package that matches: https://pkgs.alpinelinux.org/contents?branch=edge&name=mingw-w64-gcc-base&arch=x86&repo=community For some reason I'm not getting the right files with the install though:
apk add mingw-w64-gcc-base --repository http://dl-cdn.alpinelinux.org/alpine/edge/community/
bash-5.1# apk info -L apk add mingw-w64-gcc-base | grep usr/bin
usr/bin/x86_64-w64-mingw32-cpp
usr/bin/x86_64-w64-mingw32-gcc
usr/bin/x86_64-w64-mingw32-gcc-11.2.0
usr/bin/x86_64-w64-mingw32-gcc-ar
usr/bin/x86_64-w64-mingw32-gcc-nm
usr/bin/x86_64-w64-mingw32-gcc-ranlib
usr/bin/x86_64-w64-mingw32-gcov
usr/bin/x86_64-w64-mingw32-gcov-dump
usr/bin/x86_64-w64-mingw32-gcov-tool
usr/bin/x86_64-w64-mingw32-lto-dump
So instead, I tried to install with the x86_64-w64-mingw32-gcc, modified the makefile:
#CROSS := i686-pc-mingw32-
CROSS := x86_64-w64-mingw32-
The source code folder structure is:
/SRC/ide_files
/SRC/include
/SRC/src
the make file is:
/SRC/ide_files/testApp/makefile
I then try:
make -f ide_files/testApp/makefile
It errors with:
x86_64-w64-mingw32-gcc -ggdb3 -feliminate-unused-debug-symbols -gno-strict-dwarf -shared -lm -o testExec.dll -Wl,--out-implib,testExec.a <A lot of .o files>
Error relocating /usr/lib/gcc/x86_64-w64-mingw32/11.2.0/../../../../x86_64-w64-mingw32/bin/ld: qsort_r: symbol not found
collect2: error: ld returned 127 exit status
make: *** [ide_files/testApp/makefile:127: testExec] Error 1
I have a project in c++ that I want to be reasonably portable, and can be compiled by issuing a single "make" command. I currently use boost headers for certain operations, but now need "filesystem" from boost, which requires compilation.
I know there is a way to compile boost using the included shell script, but that takes FOREVER. I am curious of a way to selectively compile boost libraries, as specified from a makefile and include them in the linking process.
My current general idea is:
Have a makefile variable of the boost libraries wanted to be compiled and included.
Compile those libraries (before any dependent projects) from a boost distribution folder, AND output compiled binaries to a specific folder in the makefile project (eg: a "lib" folder)
I understand how to have these files included in the project by using:
-Llib
What is the best way to do this, as well as choose where the boost output from compilation is? Should the files be .a or .o files? (or no extension?)
This is the wilder older brother of the prior answer's manual makefile. Given a path to the BOOST distro, BOOST_DISTRO, it finds the relevant source files for the target libs specified in TARGET_BOOST_LIBS, compiles them into $(WORK_FOLDER)/<lib>/, and archives the resulting objects into $(DEST_FOLDER)/libboost_<lib>.a.
BOOST_DISTRO=.
DEST_FOLDER=libs
WORK_FOLDER=build
TARGET_BOOST_LIBS=\
system \
filesystem \
serialization
.PHONY: all
all: $(foreach lib,$(TARGET_BOOST_LIBS),$(DEST_FOLDER)/libboost_$(lib).a )
$(DEST_FOLDER):
mkdir -p $(DEST_FOLDER)
$(WORK_FOLDER):
mkdir -p $(WORK_FOLDER)
#####
# helper for building the .o files in WORK_FOLDER
#####
define MAKE_BOOST_LIB_COMPILE_RULES
$(foreach cppfile,$(shell ls $(BOOST_DISTRO)/boost/libs/$(1)/src/*.cpp),$(WORK_FOLDER)/$(1)/$(notdir $(cppfile:.cpp=.o)): $(cppfile) | $(WORK_FOLDER)/$(1)
$(CXX) $(CXXFLAGS) -D BOOST_ALL_NO_LIB \
-I$(BOOST_DISTRO)/boost \
-c $$^ \
-o $$#
)
endef
#####
# define the build rules based on the files we find in the subfolders of
# the boost distro that correspond to our library names
#####
define BUILD_BOOST_LIB
$(WORK_FOLDER)/$(1): | $(WORK_FOLDER)
mkdir -p $$#
$(call MAKE_BOOST_LIB_COMPILE_RULES,$(1))
$(DEST_FOLDER)/libboost_$(1).a: $(foreach cppfile,$(notdir $(shell ls $(BOOST_DISTRO)/boost/libs/$(1)/src/*.cpp)),$(WORK_FOLDER)/$(1)/$(cppfile:.cpp=.o)) | $(DEST_FOLDER)
ar r $$# $$^
ranlib $$#
endef
#####
# dynamically generate the build rules from the list of libs
#####
$(foreach lib,$(TARGET_BOOST_LIBS),$(eval $(call BUILD_BOOST_LIB,$(lib))))
.PHONY: clean
clean:
-rm -rf $(WORK_FOLDER)
-rm -rf $(DEST_FOLDER)
Testing with my ancient BOOST (#define BOOST_VERSION 105500), this builds the listed libs, and a dummy test program successfully compiles and calls boost::filesystem::absolute().
Using lockcmpxchg8b's answer, I was able to adapt it to my needs.
It was a little tricky to get makefiles to work right when recursively called, but I was able to get it to work.
SHELL = /bin/sh
# This makefile expects multiple arguments to be passed:
#
# Use the pattern: make var_name="var_value" when invoking this makefile
#
# BOOST_VER (the version suffix )
# BOOST_LIBS_TO_BUILD (space delimited list of boost libraries to build)
# BOOST_LIB_DIR (the output lib dir for the boost libraries)
# BOOSTDIR (the base directory to build from)
#
# Compile Info
CXX = g++
CXXFLAGS = -Wall -std=c++11
WORK_FOLDER = obj_boost$(BOOST_VER)
.PHONY: all
all: $(foreach lib,$(BOOST_LIBS_TO_BUILD),$(BOOST_LIB_DIR)/libboost_$(lib).a )
$(BOOST_LIB_DIR):
#mkdir -p $(BOOST_LIB_DIR)
$(WORK_FOLDER):
#mkdir -p $(WORK_FOLDER)
#####
# helper for building the .o files in WORK_FOLDER
#####
define MAKE_BOOST_LIB_COMPILE_RULES
$(foreach cppfile,$(shell ls $(BOOSTDIR)/libs/$(1)/src/*.cpp),$(WORK_FOLDER)/$(1)/$(notdir $(cppfile:.cpp=.o)): $(cppfile) | $(WORK_FOLDER)/$(1)
$(CXX) $(CXXFLAGS) -D BOOST_ALL_NO_LIB \
-I$(BOOSTDIR) \
-c $$^ \
-o $$#
)
endef
#####
# define the build rules based on the files we find in the subfolders of
# the boost distro that correspond to our library names
#####
define BUILD_BOOST_LIB
$(WORK_FOLDER)/$(1): | $(WORK_FOLDER)
#mkdir -p $$#
$(call MAKE_BOOST_LIB_COMPILE_RULES,$(1))
$(BOOST_LIB_DIR)/libboost_$(1).a: $(foreach cppfile,$(notdir $(shell ls $(BOOSTDIR)/libs/$(1)/src/*.cpp)),$(WORK_FOLDER)/$(1)/$(cppfile:.cpp=.o)) | $(BOOST_LIB_DIR)
#ar r $$# $$^
#ranlib $$#
endef
#####
# dynamically generate the build rules from the list of libs
#####
$(foreach lib,$(BOOST_LIBS_TO_BUILD),$(eval $(call BUILD_BOOST_LIB,$(lib))))
.PHONY: clean
clean:
#rm -rf $(WORK_FOLDER)
#rm -rf $(BOOST_LIB_DIR)/*
#echo "---- Done Cleaning Boost Libs ----"
To call this makefile, I call it from another makefile using the following:
# Boost
BOOST_VER= _1_65_1
BOOST_LIBS_TO_BUILD = filesystem timer chrono
#relative to this file
BOOST_LIB_DIR = shared/lib_boost$(BOOST_VER)
#relative to this file
BOOSTDIR = shared/boost$(BOOST_VER)
#Subdirectories
DIRECTORIES = $(sort $(dir $(wildcard */makefile)))
.PHONY: build
build: dependencies
#$(foreach dir,$(DIRECTORIES),$(MAKE) -C $(dir);)
dependencies:
#echo "---- Build Dependencies ----"
#$(MAKE) -C shared -f build_boost_libs.mk BOOST_LIBS_TO_BUILD="$(BOOST_LIBS_TO_BUILD)" BOOST_LIB_DIR="../$(BOOST_LIB_DIR)" BOOSTDIR="../$(BOOSTDIR)" BOOST_VER="$(BOOST_VER)"
The pattern to CORRECTLY invoke a recursive make is:
$(MAKE) -C subdir_of_makefile -f makefile_name.mk
The use of $(MAKE) is the proper way to invoke make (as per documentation -- it ensures the same make command is used as the top-most make) and to correctly change the running directory, you need to use the -C argument (otherwise the directory context of any sub-make is the top-most parent makefile in the call stack). The -f option specifies a makefile that is anything but a default name for a makefile. This takes into account the -C option when looking for the named makefile.
I also found out that passing "arguments" to a makefile is a bit tricky, and is usually done with export and unexport, but the problem with those is due to ONLY the LAST "status" of a variable to be exported is used for the ENTIRE makefile. You can't export a variable, call a sub-make, then unexport. It would be unexported for the entire makefile run (as the last "status" of the variable was to be unexported despite it being called after the sub-make). Variable "status" is computed/parsed before the makefile executes.
Thanks for the help! I appreciate it. I'll also be releasing this makefile in an open-source project in the future (I'll credit your username as helping with that)
I have a makefile that I personally didn't write, and I'm not very good at bash scripting and makefiles in general, so forgive me for my lack of knowledge beforehand;
AS the title states I simply want to move my executables when compiled to a ../bin/ folder. My attempt at this (shamelessy copied from another post here on SO) is given below (i.e. i tried making a phony install which should move the files, but alas it doesnt."
CXX = g++
CC = g++
# Define preprocessor, compiler, and linker flags. Uncomment the # lines
# if you use clang++ and wish to use libc++ instead of libstd++.
CPPFLAGS = -std=c++11 -I..
CXXFLAGS = -g -O2 -Wall -W -pedantic-errors
CXXFLAGS += -Wmissing-braces -Wparentheses -Wold-style-cast
CXXFLAGS += -std=c++11
LDFLAGS = -g -L..
MV = mv
PROG_PATH = ../bin/
#CPPFLAGS += -stdlib=libc++
#CXXFLAGS += -stdlib=libc++
#LDFLAGS += -stdlib=libc++
# Libraries
#LDLIBS = -lclientserver
# Targets
PROGS = myserver myclient libclientserver.a
all: $(PROGS)
# Targets rely on implicit rules for compiling and linking
# The dependency on libclientserver.a is not defined.
myserver: myserver.o messagehandler.o server.o connection.o database_memory.o database_file.o
myclient: myclient.o connection.o server.o messagehandler.o
libclientserver.a: connection.o server.o
ar rv libclientserver.a connection.o server.o
ranlib libclientserver.a
# Phony targets
.PHONY: all install clean
all: $(PROGS) install
install: $(MV) $(PROGS) $(PROG_PATH)
# Standard clean
clean:
rm -f *.o $(PROGS)
# Generate dependencies in *.d files
%.d: %.cc
#set -e; rm -f $#; \
$(CPP) -MM $(CPPFLAGS) $< > $#.$$$$; \
sed 's,\($*\)\.o[ :]*,\1.o $# : ,g' < $#.$$$$ > $#; \
rm -f $#.$$$$
# Include the *.d files
SRC = $(wildcard *.cc)
include $(SRC:.cc=.d)
So how would I best do this? The compiler says
make: *** No rule to make target `mv', needed by `install'. Stop.
A makefile rule consists of two parts, a declaration of the rule's dependencies and the commands to invoke.
The dependencies are listed on the first line of the rule after the colon and the commands to execute are listed on subsequent lines, all indented with tabs.
Your install rule needs to depend on the programs which you are moving and possibly the destination directory (you may want a rule that creates the destination), but not the mv utility itself as you don't need to build that.
install: $(PROGS)
mv $(PROGS) $(PROG_PATH)
Note that although I've used four spaces, the indentation needs to be a tab. As you don't (yet?) have a rule to make PROG_PATH, I've left it out of the dependency list.
Also note that with this rule, make will have to rebuild your programs if you invoke make twice as they will have moved. You way want to consider using cp or install instead of mv.
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.
What approach do C++ programmers on Unix platform use to create and manage Makefiles?
I was using hand made Makefiles for my projects but they don't handle header file changes and other dependencies. I googled around and found a good solution here.
But I ran into a problem here in the sed command -
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
The problem is with the 3rd expression "-e 's/ *\$$//'.
It doesn't work. Its supposed to remove trailing backslashes. I understand that there has to be double dollar there since this is part of a Makefile. Can someone tell me what wrong here?
Here's the complete Makefile -
CC=g++
CFLAGS=-g -Wall
LIBS=-lpthread
OBJS=file1.o file2.o
TARGET=testProg
$(TARGET) : $(OBJS)
$(CC) -o $# $^ $(CFLAGS) $(LIBS)
%.o : %.cpp
$(CC) -MMD -c -o $# $< $(CFLAGS)
#cp $*.d $*.P; \
sed -e 's/#.*//' -e 's/^[^:]*: *//' -e 's/ *\\$$//' \
-e '/^$$/ d' -e 's/$$/ :/' < $*.d >> $*.P; \
rm -f $*.d
-include $(OBJS:%.o=%.P)
clean :
rm -f $(TARGET) $(OBJS)
all : $(TARGET)
Apart from the solution to this problem, I would also like some tips/pointers to my 1st question.
gcc/g++ can generate dependencies for you with the -M family of options.
The following works by specifying how to generate .depends files given a source file. By doing -include $(DEPS) $(DEPS) is recognized as a target and will be built/rebuilt when the source files change.
CXX = g++
CXXFLAGS = -Wall -O3
LDFLAGS =
TARGET = testcpp
SRCS = main.cc x.cc foo.cc
OBJS = $(SRCS:.cc=.o)
DEPS = $(SRCS:.cc=.depends)
.PHONY: clean all
all: $(TARGET)
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $(LDFLAGS) $(OBJS) -o $(TARGET)
.cc.o:
$(CXX) $(CXXFLAGS) -c $< -o $#
%.depends: %.cc
$(CXX) -M $(CXXFLAGS) $< > $#
clean:
rm -f $(OBJS) $(DEPS) $(TARGET)
-include $(DEPS)
I use that approach too and can't praise it highly enough. And I write my makefiles by hand and reuse them a lot on new projects.
.The expression "s/ *\\$//" will work outside the context of Make. Within a makefile it doesn't work because Make tries to interpret "$/" before handing the result to the shell. So you must use "s/ *\\$$//" (note the extra $) within the makefile, but this won't work outside the context of Make (so testing it is a slight pain).
EDIT:
I've tried your makefile, and that sed statement seems to remove trailing backslashes just fine. Try something simpler, like this:
backslash:
#echo " \\" > $#
test: backslash
#echo without sed:
#cat backslash
#echo with sed:
#sed -e 's/ *\\$$//' < backslash
EDIT:
All right, now I'm hooked. Could you try these experiments and tell us the results?
Change the last character to 'z' : s/.$/z/
Change a trailing backslash to 'z' : s/\\$/z/
Change a trailing backslash to 'z' : sm\\$mzm
Delete a trailing backslash : s/\\$//
Delete spaces and a trailing backslash: s/ *\\$//
Try all of these inside and outside of Make, with '$' and '$$'.
In a make file anything you list on the dependency line is a dependency header files or other files included.
BSD tutorial on make Note: you can auto generate header dependency info with the -MM switch of GCC.
I must be missing something. Why doesn't generating dependency files work for you?
I prefer to use CMake, even though it's not strictly the solution to your problem.
It's a project description language that'll generate your Makefiles, Visual Studio Project, Eclipse Project, KDevelop, etc for you. All the dependencies are done for you:
CMakeLists.txt
add_executable(my_exe file1.c file2.c)
target_link_libraries(my_exe my_library)
add_subdirectory(lib)
In lib/CMakeLists.txt
add_library(my_library file3.c file4.c)
This creates a my_exe from file1.c file2.c linked against my_library. I find this much simpler. It also has things like package discovery:
find_package(Qt4)
The makedepend utility is installed on many systems and can be quite useful for generating dependency information.
Here is an example Makefile that uses the include directive (plus a little Perl magic) to incorporate the output from makedepend:
# the name of the executable that we'll build
TARGET = foo_prog
# our .cc source files
SRCS = foo.cc main.cc
# the .o versions of our source files
OBJS := $(patsubst %.cc, %.o, $(filter %.cc, $(SRCS)))
# some flags for compiling
CXXFLAGS = -Wall -Werror
# In order to build $(TARGET), we first build each of the $(OBJS).
# Then we use the given command to link those $(OBJS) into our
# $(TARGET) executable. $^ is a shortcut for $(OBJS). $# is a
# shortcut for $(TARGET).
#
# The default compile rule will compile each of the $(OBJS) for us.
$(TARGET): $(OBJS)
$(CXX) $(CXXFLAGS) $^ -o $#
# Use "make clean" to remove all of the support files.
clean:
rm -f $(OBJS) $(TARGET) Makefile.depend *~
# This automatically uses the 'makedepend' utility to add any
# dependencies that our source files have, namely .h files. This way,
# if the .h files change, the code will be re-compiled.
include Makefile.depend
Makefile.depend: $(SRCS)
makedepend -f- -Y $(SRCS) 2> /dev/null | \
perl -p -e "s/(^.*?:)/Makefile.depend \1/" > Makefile.depend
If both foo.cc and main.cc depend on foo.h, then the contents of Makefile.depend would be:
Makefile.depend foo.o: foo.h
Makefile.depend main.o: foo.h
The end result is that the dependency information from makedepend is injected into the Makefile as a series of rules. It's similar to the approach of using a .d file for each .cc file, but keeps the dependency information in one file instead of scattered all over the place.
In Mozilla's build system, we use GCC's -MD switch to generate the dependency files:
http://mxr.mozilla.org/mozilla-central/source/configure.in#7134
and then we use a script called mddepend.pl to check for removed header files, such that
removing a header simply causes a rebuild, not an error:
http://mxr.mozilla.org/mozilla-central/source/config/rules.mk#2066
http://mxr.mozilla.org/mozilla-central/source/build/unix/mddepend.pl
That script generates an .all.pp file containing all the dependencies, with extra foo.o: FORCE dependencies stuck in for missing header files. We then simply -include the .all.pp file in rules.mk right below there.
You can use qmake to generate Makefiles for a project even if that project is not using Qt.
I use BSD make (pmake?) which does lot of work for me (my lang is C, but I think no difference here). This is my common 'local.prog.mk', I never change it:
.PHONY: tags .depend
# .depend depends only on $(SRCS) in bsd.dep.mk, so we can't track changes of
# header's own dependencies properly. so .depend is .PHONY target here.
CSTD ?=c99
WARNS ?=9
.if !empty(PC_LIST)
PC_CF !=pkg-config --cflags $(PC_LIST)
PC_LD !=pkg-config --libs $(PC_LIST)
.endif
CFLAGS +=$(PC_CF) -fgnu89-inline
.if !defined(NO_DEBUG)
CFLAGS +=-O0 -ggdb3
.endif
LDFLAGS +=$(PC_LD)
CTAGS =exctags
NO_MAN=
NO_OBJ=
CLEANFILES+=$(PROG).core
.include <bsd.prog.mk>
$(PROG): $(SUBDIR)
build: clean cleandepend depend all
run: $(PROG)
./$(PROG)
Note 'bsd.prog.mk' inclusion -- this handles all, build, depend, clean targets. Project-specific BSDmakefiles are simple:
.SILENT:
PROG =hello
SRCS =hello.c world.c
PC_LIST =gtk+-2.0 gnet-2.0
.include "../local.prog.mk"
proto:
cproto -siv `pkg-config --cflags $(PC_LIST)` $(SRCS) > prototypes
CLEANFILES+=prototypes
I just make depend every time I insert/remove any #include directives.
Instead of the sed scripts, use gcc's -MT option to modify the target of the generated dependency rules. This blog post has more info.
With a more modern version of GCC, you can add the -MP flag to have GCC generate empty rules for the headers itself.
I top tip that I have found useful when building dependency files is to include the dependency file as a target in the generated rule:
file.d file.o : file.c header.h header2.h ...
Thus make will regenerate the dependencies if the source or any of the headers change. Including phony targets for the headers (GCC -MP) should then allow stable builds when headers are removed - the absense of required header remains a compilation error, not a make dependency error.
Assuming that dependency files are generated into the same directory as the object files, the following should work for GCC on Unix:
-include $(OBJ:.o=.d)
$(OBJDIR)/%d : $(SRCDIR)/%.cpp
mkdir -p $(#D)
echo -n "$# " > $#.tmp
$(CXX) $(CPPFLAGS) -MM -MP -MT $(#:.d=.o) $< >> $#.tmp
mv $#.tmp $#
(from memory)