Makefile for several binaries and libs from different dirs - c++

There is a project layout:
.
├── bin # <= executables go here
├── build # <= object files created here
├── lib # <= libraries go here
├── Makefile
├── src
│   ├── bin1 # <= if there is no "lib" prefix
│   ├── bin2 # <= it must be considered as executable
│   │   ├── a.c
│   │   ├── b.c
│   │   └── foo.h
│   ├── include # <= shared .h files, nothing to build here
│   ├── libt1 # <= if there is "lib" prefix - it must be
│   │   ├── blah.c # a library
│   │   └── blah.h
│   └── libt2
└── test
So i want gnu make to go through every directory in src with "lib" prefix and build a static and shared library with the same name as a directory, i.e. libt1.so and libt1.a and put them all in lib directory. Let's assume the libraries aren't linked with each other so the don't depend on each other either.
After building libs, it must go through every directory except include, and bin an executable with the same name as the directory has, and put it into bin dir. build directory is used for temporary object files.
What is the best way to do this with gnu make? I want rely on implicit rules as much as it's possible.
So now i just collect all directories into variables:
LIBS_TO_BUILD=$(wildcard $(SOURCES_DIR)/lib*)
BINS_TO_BUILD=$(filter-out $(INCLUDE_DIR) $(LIBS_TO_BUILD),\
$(wildcard $(SOURCES_DIR)/*))
But i can't figure out how to do all other steps, how should i iterate by all dirs? Assuming, that if i'll do it "by hands" it will look like:
lib/libt1.a:
$(CC) -o build/libt1.o $(CFLAGS) -c $(wildcard $(SOURCES_DIR)/libt1/*.c)
ar rcs lib/libt1.a build/libt1.o

Related

How to configure an AzerothCore module to link with the external library?

I am developing a module, which depends on another library(wasmtime). I put files into:
modules/mod_wasm/src/include - header files, and
modules/mod_mine/src/lib/libwasmtime.a - the compiled library.
The problem which I faced is that when I compile the acore server with
./acore.sh compiler all
it gives me the error:
[100%] Linking CXX executable worldserver
/usr/bin/ld: ../../../modules/libmodules.a(ModWasm.cpp.o): in function `readWasmFile(char const*)':
ModWasm.cpp:(.text+0x63): undefined reference to `wasm_byte_vec_new_uninitialized'
/usr/bin/ld: ModWasm.cpp:(.text+0xce): undefined reference to `wasm_byte_vec_delete'
The question is it required somehow add to a config that library? If yes, then how to do that?
I was testing my code in simple main.cpp file and it was working with options like "-L${workspaceFolder}/lib" and "-lwasmtime".
Maybe, these options are also required for my module?
Here is a link to azerothcore project which I use.
my module locates in modules/mod-wasm folder
azerothcore-wotlk/modules ‹master*› » tree -L 3 mod-wasm
mod-wasm
├── CMakeLists.txt
├── LICENSE
├── Makefile
├── README.md
├── conf
│   ├── conf.sh.dist
│   └── wasm.conf.dist
├── include.sh
├── mod-wasm.cmake
├── setup_git_commit_template.sh
├── src
│   ├── ModWasm.cpp
│   ├── include
│   │   ├── doc-wasm.h
│   │   ├── wasi.h
│   │   ├── wasm.h
│   │   ├── wasmtime
│   │   ├── wasmtime.h
│   │   └── wasmtime.hh
│   ├── lib
│   │   ├── libwasmtime.a
│   │   └── libwasmtime.so
│   └── wasm_loader.cpp
└── wasm_modules
└── rust_wasm_app.wasm
As I understood from the logs what I see and because CMakeList.txt exists in modules folder, the project considers the folder as module. Which in its turn scans subdirs for *.cmake files and configures the project.
The question now is how to properly configure my module to show that it contains the compiled library wasmtime inside src/lib folder?
As I understood, I could use target_link_libraries, but it requires a target name, and I have no idea what it should be and where I can take it.
At the end, I was able to find an answer with try and catch.
Azerothcore modules supports modname.cmake file to be run when configure libmodules.a which contains all extra modules(if I understood it correctly.
this is part of modules/CMakeFiles.txt
# Enables Devs to Include a cmake file in their module that will get run inline with the config.
foreach(SOURCE_MODULE ${MODULES_MODULE_LIST})
message("SOURCE_MODULE: ${SOURCE_MODULE}")
include("${CMAKE_SOURCE_DIR}/modules/${SOURCE_MODULE}/${SOURCE_MODULE}.cmake" OPTIONAL)
endforeach()
here I have my dirty cmake file which allow me to compile the server
set(WASM_MODULE_DIR ${CMAKE_SOURCE_DIR}/modules/${SOURCE_MODULE})
set(WASM_MODULE_SRC_DIR ${WASM_MODULE_DIR}/src)
message("--------------------->>>>> APPLICATION_NAME : ${APPLICATION_NAME}")
message("--------------------->>>>> APP_PROJECT_NAME : ${APP_PROJECT_NAME}")
message("--------------------->>>>> SOURCE_MODULE : ${SOURCE_MODULE}")
message("--------------------->>>>> WASM_MODULE_DIR : ${WASM_MODULE_DIR}")
message("--------------------->>>>> WASM_MODULE_SRC_DIR : ${WASM_MODULE_SRC_DIR}")
# include wasmtime
target_include_directories(modules PUBLIC ${WASM_MODULE_SRC_DIR}/include)
target_link_directories(modules PUBLIC ${WASM_MODULE_SRC_DIR}/lib)
find_library(LIBWASMTIME_TO_INCLUDE NAMES wasmtime PATHS ${WASM_MODULE_SRC_DIR}/lib REQUIRED)
message("--------------------->>>>>>>>> LIBWASMTIME_TO_INCLUDE: ${LIBWASMTIME_TO_INCLUDE}")
target_link_libraries(modules PUBLIC wasmtime)
So, it compiles now.
But I have next problem, which I am trying to resolve. but this is another story.
Thank you all for the help

Meson targets that depend on subdir siblings

Here is my project structure:
.
├── include
├── src
│   ├── abc
│   │   ├── include
│   │   └── src
│   ├── def
│   │   ├── include
│   │   └── src
│   └── ghi
│   ├── include
│   └── src
└── vendor
├── bar
│   ├── include
│   └── src
└── foo
16 directories
I would like to port my build to Meson. However, I'm not sure how to link targets defined in sibling folders.
My dependency graph looks like this:
src/abc/meson.build defines a static library abc
src/def/meson.build defines a static library def that depends on abc and foo
src/ghi/meson.build defines a static library ghi that depends on bar
vendor/bar/meson.build defines a static library bar
vendor/foo/meson.build defines a static library foo
The top-level meson.build defines an executable app that depends on abc, def and ghi
In the documentation, there seem to be two mechanisms:
subdir
subproject
It is not clear to me which is best here. I do not have any dependencies outside of my source-code.
What should I write in my meson.build files to link these targets together?
You can use subdir from the top-level meson.build file down. All variables you declare in the subdir meson.build files are available to later meson.build files. As long as you get the order of subdir calls correct, it will work.
Besides #sdgfsdh's (correct) answer, another approach I like is to define libraries and executables only in the top-level meson file, and use subdir calls to define a sets of source files and "local" include paths. Done this way, the subdir files don't implicitly depend on each other; the entire dependency tree lives in the top-level meson file.
The advantages of this approach are:
subdirs don't need to know their own path (files() and include_directories() will track this for you)
The top-level file only needs to know subdir paths to call the subdir meson files. After that, you can define everything in terms of variables created in the subdirs
subdir files don't directly depend on any other meson files
Disadvantages:
The top-level file is more cluttered
Variable names in subdir files need to be globally unique, since everything is ultimately defined in the top-level scope
An example for your case:
# Top-level meson.build
subdir('src/abc')
subdir('src/def')
subdir('src/ghi')
subdir('vendor/foo')
subdir('vendor/bar')
libabc = static_library('abc', abc_files, include_directories: abc_includes)
libabc_dep = declare_dependency(include_directories: abc_includes, link_with : libabc)
libfoo = static_library('foo', foo_files, include_directories: foo_includes)
libfoo_dep = declare_dependency(include_directories: foo_includes, link_with : libfoo)
libdef = library('def', def_files, include_directories: def_includes, dependencies : [ libabc_dep, libfoo_dep])
# src/abc/meson.build (others would be similar)
abc_files = files(['1.c','2.c',...])
abc_includes = include_directories('include')

Recursive make distclean: no such file or directory

I have the following directories:
$ cd dir1
$ tree
[...]
├── autogen.sh
├── CMakeLists.txt
├── common.gmake.in
├── configure.ac
├── Makefile.am
├── src
│   ├── Makefile.am
│   ├── Makefile.in
│ ├── [...]
│   └── dir2
│   ├── CMakeLists.txt
│   ├── Makefile.am
│ ├── [...]
And in the Makefile.am of dir2, I have:
[...]
include #abs_top_builddir#/common.gmake
[...]
The first time I compile, everything works just fine. But if I want to compile a second time, because I produced a config.status file, the Makefile wants to execute a make distclean. It will execute it in dir1 and will remove the common.gmake. But as it is recursive, when it will enter in the dir2 directory, I have the following error:
Making distclean in dir2
gmake[2]: Entering directory `/dir1/src/dir2'
Makefile:1760: /dir1/common.gmake: No such file or directory
gmake[2]: *** No rule to make target `/dir1/common.gmake'. Stop.
It looks like to me the recursive target generated by automake is wrong as it wants to remove a file it already removed previously. What do you think ?

Using cmake for c++ template library

I have a project which uses cmake to build. The project has a number of submodules which build as libraries. The structure looks like this:
src
├── CMakeLists.txt
├── libA
│   ├── CMakeLists.txt
│   ├── include
│   │   └── A
│   │      └── A.h
│   └── src
│      └── A.cpp
│
├── libB
│   ├── CMakeLists.txt
│   ├── include
│   │   └── B
│   │   └── B.h
│   └── src
│      └── B.cpp
│
├── include
│   └── project.h
├── main
│   ├── CMakeLists.txt
│   └── main.cpp
└── other_main
   ├── CMakeLists.txt
   └── main.cpp
Now it turns out that I need to convert module B to be template based rather than a linkable lib; i.e. I want to export just headers from module B.
Currently module B's CMakeLists.txt contains the following:
add_library(B STATIC ${SOURCES})
target_include_directories(B
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
... other include dirs ...
PRIVATE
src)
# B depends on A
target_link_libraries(B A)
export(
TARGETS B
FILE BLibraryConfig.cmake)
What are the minimum changes I need to make to my CMakeLists files (at either module or project scope) to be able to support B as a template library given that B still depends on A and both my main projects make use of A and B?
As another answer says, you could declare B as an interface library. This approach has some limitations, though. For instance, you cannot set custom properties on interface libraries. Also B's headers might not be properly displayed by an IDE, e.g. QtCreator 4.6.1 does not show them in the project tree.
If this is critical for you, there is an alternative. You could have a static library which contains only headers, but you need to manually specify it's linker language.
add_library(B STATIC ${SOURCES})
target_include_directories(B
PUBLIC
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
... other include dirs ...
)
# As B does not have any source files, you have to explicitly
# specify the linker language
set_target_properties(B PROPERTIES LINKER_LANGUAGE CXX)
# B depends on A
target_link_libraries(B A)
export(
TARGETS B
FILE BLibraryConfig.cmake)
You can declare B as an interface library to define it as header-only. It will just require slight modifications of target_include_directories and target_link_libraries (define INTERFACE properties instead of public/private)
add_library(B INTERFACE) # no sources
target_include_directories(B INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
# other include dirs ...
)
# B depends on A
target_link_libraries(B INTERFACE A)
export(
TARGETS B
FILE BLibraryConfig.cmake
)

About No such file or directory compilation terminated error

I'm new to C++ , i have installed the lib Com++ for network programming
but when i just include the header file
#include <iostream>
#include <ComPP/ComPlusPlus>
using namespace std;
int main(int argc ,char *argv[]){
cout << "Hello World" << endl;
return 0;
}
i get the error
main.cpp:2:29: fatal error: ComPP/ComPlusPlus: No such file or directory
using fedora linux
i used this command to compile as mentioned in the manual
g++ -I ./ -L./ -o server main.cpp -lCommPP -lsys -lpthread -lrt
the directory /usr/include/ComPP/ is exist with all the header files
ComPP
├── ComPlusPlus
│   ├── AClnt.h
│   ├── ASrvContext.h
│   ├── ASrv.h
│   ├── ASrvProperties.h
│   ├── Clone.h
│   ├── Comm.h
│   ├── ComPlusPlus
│   ├── Context.h
│   ├── Daemon.h
│   ├── Directory.h
│   ├── DirEntry.h
│   ├── File.h
│   ├── Launch.h
│   ├── Mutex.h
│   ├── Poll.h
│   ├── Process.h
│   ├── SClnt.h
│   ├── Sem.h
│   ├── ShMem.h
│   ├── Signalling.h
│   ├── Socket.h
│   ├── SocketTcp.h
│   ├── SocketUdp.h
│   ├── SocketUnix.h
│   ├── SrvProperties.h
│   ├── SSrvContext.h
│   ├── SSrv.h
│   ├── SSrvProperties.h
│   └── Thread.h
└── SysPlusPlus
├── ComException.h
├── config.h
├── GenCfg.h
├── Logger.h
├── syscall.h
├── syslib.h
├── SysPlusPlus
└── Tools.h
You do not include a header file. #include <ComPP/ComPlusPlus> this is a directory. From what you posted you need to add another ComPlusPlus. #include <ComPP/ComPlusPlus/ComPlusPlus> but it very uncommon to use headers without the .h ending. So you better check the spelling of directories and files.
After carefully reading the cplusplus.com site. The error is indeed something else.
They assume that you set the include path of your compiler to ComPP. E.g as Ahmed already commented with a -I /usr/include/ComPP.
So you can either fully qualify your include in the cpp file as /usr/include/ is a standard search path for gcc or you add another path.
Nevertheless I find it very irritating to use a header without a .h ending.
When you download the comPP library there is a ProgrammersGuide.pdf in the Documentation folder. There you can find what libs are needed. The file is not 100% accurate. I got it working using this format:
g++ -I/usr/include/ComPP -lComPP -lSysPP -lpthread -lrt ExampleClient.cpp -o ExampleClient
This will only work if you have these includes:
#include <SysPlusPlus/SysPlusPlus>
#include <ComPlusPlus/ComPlusPlus>
Kind Regards,
Maarten