How to compile multiple simple projects with GNU make - gnu-make

I am trying to implement various project from a programming book. My intention was to have each project exercise in its own folder and then have a makefile that compiles all of them with something like a make all. The folder structure is like this:
.
├── Makefile
├── bin
│   ├── prog1
│ ├── prog2
│ └── prog3
└── src
├── prog1
│ ├── Makefile
│ └── main.c
├── prog2
│ ├── Makefile
│ └── main.c
└── prog3
├── Makefile
└── main.c
I would like to learn how to set up such a structure. In particular the part where the top makefile visit all folders in src calls make there, and then copies and renames the executable into the bin folders.

Your layout schematic shows a makefile for each exercise, plus the top-level makefile that you seem actually to be asking about. It would be best for the top-level makefile to avoid duplicating the behavior of the per-exercise makefiles, as such duplication would create an additional maintenance burden for you. Additionally, it is likely that you will eventually progress to exercises involving multiple source files, and perhaps to some that have multiple artifacts to be built. This is all the more reason for each per-exercise makefile to contain everything necessary to build the exercise with which it is associated (into the exercise-specific directory), and for the top-level makefile to depend on those.
Following that scheme would leave a well-defined role for the top-level makefile: to perform the per-exercise builds (by recursively running make), and to copy the resulting binaries to bin/. This is not the only way to set up a system of cooperating makefiles, but it is fairly easy, and that will allow you to focus on the exercises instead of on the build system.
Let us suppose, then, that each individual exercise can be built by changing to its directory and running make, with the result being an executable in the same directory, with the same name as the directory. That is, from the top-level directory, executing cd src/prog2; make would produce the wanted executable as src/prog2/prog2. In that case, the top-level makefile needs little more than the names of all the exercises, and a couple of rules:
EXERCISES = prog1 prog2 prog3
BINARIES = $(EXERCISES:%=bin/%)
all: $(BINARIES)
$(BINARIES):
make -C src/$$(basename $#)
cp src/$$(basename $#)/$$(basename $#) $#
Note: that uses a feature specific to GNU's implementation of make to compute the names of the wanted binaries from the exercise names. I take that to be acceptable, since you tagged [gnu-make], but in any case, it is a convenience feature, not a necessity.

There are different ways to tackle this, but something like this should work for your example:
PROGS := bin/prog1 bin/prog2 bin/prog3
all: $(PROGS)
$(PROGS):
$(MAKE) -C src/$(#F)
mkdir -p $(#D)
cp src/$(#F)/main $#
.PHONY: clean
clean:
rm -f $(PROGS)
for t in $(PROGS); do make -C src/`basename $$t` clean; done
We define a list of targets (PROGS) we are to build. We say these targets are prerequisites of all and then we go ahead and define how they should be built, that is: we recursively descent into src/ plus filename part of the target to run make there. We create directory of the target to be sure it's there and copy main from the directory we've descended to the path of the target.
For a good measure, there is a clean target as well that removes all the PROGS and runs make clean recursively in src/.

Related

How to handle dependencies with CMake

I'm trying to convert my previous qmake approach to cmake. I have a static lib called shared that links with different applications as a common ground. Each application has it's own static lib called common to link with the different targets of the same application (standalone, plugin-format-1, plugin-format-2, etc).
shared/
├── CMakeLists.txt
├── shared.cmake
│ .
project/
├── CMakeLists.txt
├── common/
├── common/CMakeLists.txt
│ common/common.cmake
│ .
When I'm developing and debbuging I want to avoid the hassle of compiling each lib individually so in debug mode I would usually include shared.pri and common.pri and when compiling the application, everything would compile smoothly, all toghether. I'm trying to replicate this include pattern using .cmake files.
#project.pro
include(../shared/shared.pri)
include(common/common.pri)
When I want to make a final and release version of the application I have a build script that compile the shared static lib, the common static lib and then links the different targets with this libs.
I have already created the CMakeLists.txt for the shared and common static libs. My problem now is how to replicate the pattern described above with cmake because when including the shared.cmake and common.cmake in the application CMakeLists.txt, the paths are not compatible. It seems that when you include(xxx.cmake), the path will always be relative to the parent CMakeLists.txt.
What would be the right way of achieving this with CMake? Is this even possible?
Use add_subdirectory() instead of include. For shared, which is "out-of-tree", you'll also need to specify the binary directory (the place to put the generated and compiled files).
add_subdirectory(../shared shared)
add_subdirectory(common)
Any targets created in those subprojects will now be available for you to link with target_link_libraries in your main project.
When you build your separate versions, consider using export() and/or install(EXPORT) to produce cmake files that you can include from your application projects instead of using add_subdirectory(), so that can be the only change you need to make.

Undefined symbol error when trying to depend on RcppAmadillo

I am trying to depend on RcppArmadillo in my package but I get an error unable to load shared object /tmp/Rtmp0LswYZ/Rinst82cbed4eaee/00LOCK-alt.raster/00new/alt.raster/libs/alt.raster.so: undefined symbol: dsyev_ when I try to run the command R CMD build . in my package directory. However, following the instructions on https://stackoverflow.com/a/14165455 in an interactive R session works correctly. I have also run the R -e 'Rcpp::compileAttributes()' in my package directory and it seems to generate the RcppExports.cpp correctly. What am I doing wrong?
As surmised in the comments above, it is really beneficial to start from a working example.
To create one, we offer the RcppArmadillo.package.skeleton() function. Use it as follows:
edd#rob:/tmp$ Rscript -e 'RcppArmadillo::RcppArmadillo.package.skeleton("demoPkg")'
Calling kitten to create basic package.
Creating directories ...
Creating DESCRIPTION ...
Creating NAMESPACE ...
Creating Read-and-delete-me ...
Saving functions and data ...
Making help files ...
Done.
Further steps are described in './demoPkg/Read-and-delete-me'.
Adding pkgKitten overrides.
>> added .gitignore file
>> added .Rbuildignore file
Deleted 'Read-and-delete-me'.
Done.
Consider reading the documentation for all the packaging details.
A good start is the 'Writing R Extensions' manual.
And run 'R CMD check'. Run it frequently. And think of those kittens.
Adding RcppArmadillo settings
>> added Imports: Rcpp
>> added LinkingTo: Rcpp, RcppArmadillo
>> added useDynLib and importFrom directives to NAMESPACE
>> added Makevars file with Rcpp settings
>> added Makevars.win file with RcppArmadillo settings
>> added example src file using armadillo classes
>> added example Rd file for using armadillo classes
>> invoked Rcpp::compileAttributes to create wrappers
edd#rob:/tmp$
It should create these files:
edd#rob:/tmp$ tree demoPkg/
demoPkg/
├── DESCRIPTION
├── man
│   ├── demoPkg-package.Rd
│   ├── hello.Rd
│   └── rcpparma_hello_world.Rd
├── NAMESPACE
├── R
│   ├── hello.R
│   └── RcppExports.R
└── src
├── Makevars
├── Makevars.win
├── rcpparma_hello_world.cpp
└── RcppExports.cpp
3 directories, 11 files
edd#rob:/tmp$

How to tar all files in current directory using tar but without inputing names of tar file and all files?

ENV:
macOS Sierra 10.12.6
Raw input(example):
.
├── f1.md
├── f2.md
├── f3.md
├── f4.txt
├── f5.csv
└── f6.doc
0 directories, 6 files
In a test folder, there are 6 files.
Expected output:
.
├── all.tar
├── f1.md
├── f2.md
├── f3.md
├── f4.txt
├── f5.csv
└── f6.doc
0 directories, 7 files
Trying and Problem
tar -cvf all.tar f1.md f2.md f3.md f4.txt f5.csv f6.doc
Though I get the result from the above method but I have to inputing all file names and the compressed file name, which is inconvenient. For example , I can select all files and right click, then choose compressed option without inputing all.tar (I don't mind the .tar filenames.)
Hope
command-line method without inputing specific file names.
In case you want all files, including those in the subdirectories (or if you have no subdirectories), you would run:
tar -cvf all.tar *
Then, bash would expand * into the list of all files in the current directory, including subdirectories.
In case you want only those files in the current directory, but NOT in the subdirectories, then you would have to use find, in a more complicated command. Let me know if this is the case for you, and I can take the time to find that combination of commands for you.

`man` can't access custom manpages

I followed these instructions to add some manpages on my computer, but I still can't open it with man.
I set $MANPATH to /usr/local/man (export MANPATH=/usr/local/man in my ~/.zshrc, and sourced it) and copied my manpage files to /usr/local/man/man3. Yet man doesn't find the pages I want to access :
$ echo $MANPATH
/usr/local/man
$ tree /usr/local/man
/usr/local/man
└── man3
├── mlx.1
├── mlx_loop.1
├── mlx_new_image.1
├── mlx_new_window.1
└── mlx_pixel_put.1
1 directory, 5 files
$ man mlx
No manual entry for mlx
$ man 3 mlx
No manual entry for mlx in section 3
Why do I get this error and what could I do?
It seems that the files are either in the wrong directory or have an incorrect extension.
The directory name indicates that it contains manpages for section 3 (Library calls) but the filename extensions suggest that the manpages belong to section 1 (Executable programs or shell commands).
You should be able to check which is the case - for example for mlx.1 - with the following command
man /usr/local/man/man3/mlx.1
This should show the name of the manpage (probably in uppercase) followed by the section number in parentheses at the very beginning.
If it shows MLX(1) move the file mlx.1 into the directory /usr/local/man/man1 (or just rename man3 if all files belong to section 1). If it shows MLX(3), just rename the file to mlx.3.

How do I write a yocto/bitbake recipe to copy a directory to the target root file system

I have a directory of 'binary' (i.e. not to be compiled) files and just want them to be installed onto my target root file system.
I have looked at several articles, none of which seem to work for me.
The desired functionality of this recipe is:
myRecipe/myFiles/ --> myRootFs/dir/to/install
My current attempt is:
SRC_URI += "file://myDir"
do_install() {
install -d ${D}/path/to/dir/on/fs
install -m ${WORKDIR}/myDir ${D}/path/to/dir/on/fs
}
I can't complain about the Yocto documentation overall, it's really good! Just can't find an example of something like this!
You just have to copy these files into your target rootfs. Do not forget to pakage them if they are not installed in standard locations.
SRC_URI += "file://myDir"
do_install() {
install -d ${D}/path/to/dir/on/fs
cp -r ${WORKDIR}/myDir ${D}/path/to/dir/on/fs
}
FILES_${PN} += "/path/to/dir/on/fs"
Take care that with a simple recursive copy, you will end up having host contamination warnings so you would need to copy with the following parameters:
do_install() {
[...]
cp --preserve=mode,timestamps -R ${S}${anydir}/Data/* ${D}${anyotherdir}/Data
[...]
}
As other recipes in poky do, or just follow the official recommendations to avoid problems with ownership and permissions.
For a recipe folder like this:
.
├── files
│   ├── a.txt
│   ├── b.c
│   └── Makefile
└── myrecipe.bb
You can use the following recipe to install it on a specific folder into your rootfs:
SRC_URI = " file://*"
do_install() {
install -d ${WORKDIR}/my/dir/on/rootfs
install -m 0755 ${S}/* ${WORKDIR}/my/dir/on/rootfs/*
}
FILES_${PN} = "/my/dir/on/rootfs/* "
I think it did not work for you becuase you forgot to add mode value, after "install -m",
see man page of install command:
https://linux.die.net/man/1/install
install -m [mode] src destination

Resources