Makefile : How to install a project with a file pkg-config - c++

I am trying to make a clean install of my c++ project :
exports the .h inside an include/ dir
compile a .dylib (macos) or .so (ubuntu) inside a lib/ dir
Now the question is : How do I write/export a pkg-config .pc file, with the makefile, that will correspond to my project. In Mac OS and Linux, so I can just call
LDFLAGS=$(shell pkg-config --libs my_project)
CPPFLAGS=$(shell pkg-config --cflags my_project)
In other makefiles, to get the flags to include.
This is what I done so far (macos):
install : $(OBJS)
mkdir -p $(INSTALL_LIB_DIR)
$(CXX) -dynamiclib $^ $(CPPFLAGS) $(LDFLAGS) -o $(INSTALL_LIB_DIR)/lib$(ENGINE_LIB_NAME).dylib
mkdir -p include
cp src/*.h include/
cp src/*.tpp include/
mv include $(INSTALL_DIR)
rm -rf include
rm -rf lib
uninstall:
#echo "Removing dir " $(INSTALL_DIR)
rm -r $(INSTALL_DIR)
Thank you very much.
If it can't be done, I will look into doing that with cmake instead...

Related

Compile and Run C++ Application in Alpine Docker Container

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

Build error: make: Nothing to be done for 'compile'

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

Header file not found (boost/bind.hpp)

I'm developing a project with boost and the preproc doesn't find the boost header files for a mysterious reason.
I'm on a xUbuntu 32 bits and I use g++ and boost 1.55.0
The error: main.cpp:1:26: fatal error: boost/bind.hpp: No such file or directory
If I comment this include, it's the next include who is not found so the problem isn't one file in particular.
The code:
#include "boost/bind.hpp" // just to be sure I test with "" and <>
#include <boost/asio.hpp>
#include <sys/types.h>
The makefile:
NAME = myProject
INSTALL_DIR = /usr/local/bin
FILES_DIR = /etc/myProject
RC_FILE = ./scripts/myproject.rc
SRC = main.cpp
OBJ = $(SRC:.cpp=.o)
CC = g++
IFLAGS = -I./boost/
LFLAGS = -pthread -L./boost/stage/lib/ -lboost_system-mt -lboost_regex-mt -lboost_filesystem-mt
RM = rm -f
all : $(OBJ)
$(CC) -o $(NAME) $(OBJ) $(IFLAGS) $(LFLAGS)
install :
mkdir -p $(INSTALL_DIR)
mkdir -p $(FILES_DIR)
cp $(NAME) $(INSTALL_DIR)
cp $(RC_FILE) /etc/init.d/
insserv $(RC_FILE)
remove :
insserv --remove $(RC_FILE)
clean :
find . -name "*~" -exec rm {} \;
find . -name "*.o" -exec rm {} \;
fclean : clean
$(RM) $(NAME)
re : clean all
.PHONY : install remove clean fclean
The main.cpp and the makefile are in whatever/myproject/
The boost library is in whatever/myproject/boost/
The boost libs (.a and .so) are in whatever/myproject/boost/stage/lib/
The boost headers are in whatever/myproject/boost/boost/
I've searched for about 2 hours, tried everything I can think of without success, so thank you very much in advance to the person who can resolve this problem.
Edit:
Bidule0hm make -n
g++ -c -o main.o main.cpp
g++ -o myProject main.o -I./boost/ -pthread -L./boost/stage/lib/ -lboost_system-mt -lboost_regex-mt -lboost_filesystem-mt
I've finally solved the problem by installing boost with apt-get instead of using it locally in the project folder.
Other answer that helped me here
Can you run make -n or make V=1 and post the output?
Second Post:
I think the include folders have to come before the -o on g++. Can you replace $(CC) -o $(NAME) $(OBJ) $(IFLAGS) $(LFLAGS)
with $(CC) -c $(IFLAGS) -o $(NAME) $(OBJ) $(LFLAGS)
A sample line from my project looks like:
g++ -c -g -I.. -I/usr/include/boost -std=c++11 "build/Debug/main.o.d" -o build/Debug/main.o main.cpp
First post:
For laughs, try doing -I/full/path/to/boost.
Often with these issues, its more of a case of the "." not being the directory you think it is.
Please also post up what platform you're on(windows, Linux), and the makefile :)

Linking boost libraries in makefile under cygwin

I'm trying to link my program with boost libraries using makefile with cygwin. Here is my makefile:
CXX = g++
CXXFLAGS = -Wno-signed-compare -Wall -std=c++11 -funsigned-char -I /cygdrive/e/boost/include/boost-1_55/boost
LNKFLAGS = -L cygdrive/e/boost/lib
SRCDIR = src
OUTDIR = bin
EXEC = $(OUTDIR)/prg
SOURCES = $(wildcard src/*.cpp)
OBJECTS := $(SOURCES:$(SRCDIR)/%.cpp=$(OUTDIR)/%.o)
all: $(EXEC)
$(EXEC): $(OBJECTS)
$(CXX) $(LNKFLAGS) $(OBJECTS) -o $(EXEC) -l boost_thread
$(OBJECTS): $(OUTDIR)/%.o : $(SRCDIR)/%.cpp
mkdir -p $(OUTDIR)
$(CXX) $(CXXFLAGS) -c -O3 $< -o $#
clean:
rm -rf $(OUTDIR)
.PHONY: clean
Result:
$ make
g++ -L cygdrive/e/boost/lib bin/test.o -o bin/prg -l boost_thread
c:/mingw/bin/../lib/gcc/mingw32/4.8.1/../../../../mingw32/bin/ld.exe: cannot find -lboost_thread
What's wrong? What should I specify?
In your Makefile the library search path is relative, but should be absolute in this case.
LNKFLAGS = -L/cygdrive/e/boost/lib
Check if /cygdrive/e/boost/lib really contains Boost libraries built with the GCC toolchain.
libboost_thread.a or libboost_thread.so will work.
Libraries built with the Visual C++ toolchain ending with .lib or .dll will not work.
Check if the filename matches.
-lboost_thread requires that the library is named either libboost_thread.a or libboost_thread.so.
libboost_thread-mt.a or the like will not work.
You may find my answer to a related question helpful.

Makefile target always up to date with code generation

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.