Unix command line: find different behaviour from dir to dir - unix

I'm using a find command in a makefile like so:
CC = clang++
CODE = $(shell find . -name *.cpp) #find command here !!!!!!
EXEC = tcr_translator
.PHONY: all clean
all: $(OBJECT)
clear
$(CC) $(CODE) -o $(EXEC) -I src/
clean:
rm $(EXEC)
run: all
./tcr_translator
So, this find command list all the cpp file to compile, makes it easier than to hard-write them in my makefile. This worked perfectly for my last project, so I took the same makefile for my new project. My problem, now the find command (which is, char for char, the same command) won't look into my subdirectories.
So if I have .cpp in a src/ subfolder, it won't find them.
Why would such a command work in a certain directory and not in an other. I'm really at a loss here :(

You should quote the *.cpp to avoid it from being expanded by shell before passed into find.
CODE = $(shell find . -name '*.cpp')

Related

Makefile to render all targets of all .Rmd files in directory

My aim is to have a universal Makefile which I can copy into each directory where I have an RMD file, which will, upon calling make in this directory, render all targets defined in all .Rmd files in this directory.
The Makefile below works for only renders the last file as expected. I am sure I am doing something simple wrong.
How do I have to modify the Makefile so that it does what it is supposed to do?
Also: when I run make a second time, all files are generated again, although no SOURCE files changed.
I have the following Makefile:
SOURCES=$(shell find . -name "*.Rmd")
TARGETS_pdf=$(SOURCES:%.Rmd=%.pdf)
TARGETS_html=$(SOURCES:%.Rmd=%.html)
TARGETS_nb_html=$(SOURCES:%.Rmd=%.nb.html)
TARGETS_docx=$(SOURCES:%.Rmd=%.docx)
default: $(SOURCES)
$(info Generating defined targets from $(SOURCES))
#echo "$< -> $#"
#Rscript -e "rmarkdown::render('$<', output_format = 'all')"
clean:
rm -rf $(TARGETS_pdf)
rm -rf $(TARGETS_html)
rm -rf $(TARGETS_nb_html)
rm -rf $(TARGETS_docx)
Thanks.
When you run make it executes the first rule it finds. In your case it is default. It checks then if this file exists. If it does not, the script is run, which is supposed to generate the target file (default). Your script does not do that. That is why next time make runs, it starts all over again. If the file exists, the script does not need to be run.
What you could do is this:
SOURCES=$(shell find . -name "*.Rmd")
TARGET = $(SOURCES:%.Rmd=%.pdf) $(SOURCES:%.Rmd=%.html) $(SOURCES:%.Rmd=%.nb.html) $(SOURCES:%.Rmd=%.docx)
%.docx %.nb.html %.html %.pdf: %.Rmd
Rscript -e "rmarkdown::render('$<', output_format = 'all')"
default: $(TARGET)
clean:
rm -rf $(TARGET)

Makefile run an action before everything

For building my target I have a list of prerequisites contained in a file list.txt and a script for generating this file generate-list.sh.
I need the script to be executed as first thing every time I invoke the make in order to have the list.txt updated and to give ti make the right list of prerequisites.
prebuild:
touch list.txt
.SECONDEXPANSION:
exe: prebuild $$(shell cat list.txt)
touch exe
<files in list.txt>:
<rules for generating these files>
In this way when I run make I first get an error from cat saying that list.txt does not exist, then list.txt is generated but since the cat failed the prerequisites contained in list.txt are not generated.
One method you could use, given that generate_list.sh must be executed at the very start every time, would be to explicitly execute it using the shell function. This would mean altering your makefile to something like
$(shell ./generate_list.sh > /dev/null)
.SECONDEXPANSION:
exe: $(shell cat list.txt)
touch exe
#echo $?
<files in list.txt>:
<rules for generating these files>
Executing this makefile produces
$ make
touch exe
deps.c test.c
where my generate_list.sh file contains
#!/bin/bash
touch test.c deps.c
echo deps.c test.c > list.txt
echo 'Created prerequisites list.'
Notes
/dev/null is included in $(shell ./generate_list.sh > /dev/null) incase your generate_list.sh produces an output as this would cause an error in make of
$ make
GNUmakefile:1: *** missing separator. Stop.
otherwise.
#echo $? shows that all of the prerequisites in list.txt are now included as prerequisites of exe.
Alternate Method Based on Auto Dependency Generation
What you are attempting to do is very similar to automatic dependency generation which can be accomplished using the -include directive in make. For future usage you may want to consider going down this route and altering your generate_list.sh script to create a makefile that can be included in your main makefile.

Change directory in makefile for main shell

I have a following scenario in my build system.
1. 1000 makefiles in src directories
2. There is common.make file being included for all 1000 makefiles
3. links were created for makefiles and sources in object directory from source directory. Hence all makefiles and many more scripts inside makefile are written in such a way as it exists in build directory.
4. obj directory is the dynamic location.
5. Now I removed all links.no more links in object directory.
6. I want to execute all makefiles in source directory where I expect to change the object directory (dynamic directory name) before executing. (I can't use make -C here, because I do not know what directory to change). I can set VPATH for finding sources.
7. I want to make use common.make to change the directory dynamically, but whatever cd, $(shell cd ...) I do in common.make is not reflected in main Makefile.
8. If I do not do this, I will end up in modifying all 1000 makefiles. I do not want to do this.
Please let me know the best of way of doing it. In simple words, I want to change the directory (through common.make) before executing my 1000 makefiles,
I expect common.make to do the following.
1) save srcpath = current path (current path is source directory)
2) Change to output directory (Directory name is dynamic here).
3) set VPATH=srcpath
4) now any makefile in source directory can make use of common.make to compile and have the binaries and objects in output directory.
# This is one of the sample Makefile. I have shortened this file. All makefiles are not using the same names like SRCS, CMDSRCS. It would be different.
# this is existing makefile. Source location /home/user/project/src/mod1/lib/resmgr>make BD=100. I want the output to
# /home/user/project/build/swout100/mod1/lib/resmgr/*. common.make (common make) might validate the argument BD here. BD=101 is not allowed.
# We can force the user to do make -C /home/user/project/build/swout100/mod1/lib/resmgr (no BD validation here. user should know what directory to go).
# I would expect common.make would help the user as utility makefile
TOPDIR = ../../..
MAKEDIR = $(TOPDIR)/make
include $(MAKEDIR)/common.make # It is included in most makefiles. This can be treated as common makefile. I thought of modifying common.make
include ........ #(More includes here)
TARGET = resmgrd
CMDSRCS = resmgr_cli.c \
resmgrlogshow.c \
# more source files here
CMDOBJS = $(CMDSRCS:.c=.o)
CMDHNDLR = resmgrcmd
#... CFLAGS here and library flags here
MDSRC = main.c
SRCS = resmgr.c \
# more source files here
HDRS = resmgr.h
MDOBJ = $(MDSRC:.c=.o)
OBJS = $(SRCS:.c=.o)
$(OBJS) $(MDOBJ) $(CMDOBJS): $(HDRS)
DEPENDSRCS = $(MDSRC) $(SRCS) $(CMDSRCS)
ST_LIBS = $(DEVOSLIBSRC)/apixdr/libapixdr.a
$(TARGET): $(MDOBJ) $(OBJS)
$(CC) $(LDFLAGS) -o $# $^ $(LDLIBS) $(ST_LIBS)
$(CMDHNDLR): $(CMDOBJS)
$(CC) $(LDFLAGS) -o $# $^ $(DEVOSLIBS) $(IPCLIB) $(KILIB) $(MIAUXLIB) \
$(RESMGRLIB) $(RBACLIB)
install:: install-server
install-server: $(TARGET) $(TARGET).options $(DEVOSSBINDIR) $(DEVOSCONFDIR)
$(INSTALL) -m 755 $(TARGET) $(DEVOSSBINDIR)
install-commands: $(DEVOSBINDIR)/$(CMDHNDLR) \
install-admin-cmds install-user-cmds
clean::
$(RM) $(OBJS) $(TARGET) $(SCRIPTS) $(RAWMAN) $(CMDHNDLR) $(ZIPMAN)
I found an answer to my question.
http://make.paulandlesley.org/multi-arch.html

How can I get make to put the binaries in a different location?

Short and easy question, but I seem to have a writer's block here:
Suppose I have a source code file in the same directory as the makefile I use to build the program:
confus#confusion:~/prog$ ls
binaries includes main.c Makefile
How do I get make to put the binaries for my main.c in the binaries dir? Afterwards on a second run make should see if the binary file there is up to date (and don't compile it again) just like normal.
My thought was something like this:
# Makefile
.PHONY: all
SOURCES := $(wildcard *.c)
TARGETS := $(subst %.c,binaries/%.o,$(SOURCES))
all:$(TARGETS)
$(TARGETS):$(SOURCES)
./compile "$(subst .o,.c,$(#F))" -o "$#"
Don't say all targets depend on all sources, instead have a pattern rule
binaries/%.o: %.c
./compile ... -o $# -c $<
you may also need to use a vpath
Revised:
You also had a problem with your subst ...
this test worked (just for compiling individual .o files, you still need to link them, which would be a very simple rule)
# Makefile
.PHONY: all
SOURCES := $(wildcard *.c)
TARGETS := $(patsubst %.c,binaries/%.o,$(SOURCES))
all:$(TARGETS)
binaries/%.o: %.c
$(CC) -o $# -c $<

Call cmake from make to create Makefiles?

I am using cmake to build my project. For UNIX, I would like to type make from my project's root directory, and have cmake invoked to create the proper Makefiles (if they don't exist yet) and then build my project. I would like the cmake "internal" files (object files, cmake internal Makefiles, etc.) to be hidden (e.g. put in a .build directory) so it doesn't clutter my project directory.
My project has several sub-projects (in particular, a library, a user executable, and a unit test executable). I would like Makefiles (i.e. I type make and this happens) for each sub-project to execute cmake (as above) and build only that sub-project (with dependencies, so the library would be built from the executables' Makefiles, if needed). The resulting binary (.so library or executable) should be in the sub-project's directory.
I made a Makefile which does the main project bit somewhat well, though it feels somewhat hackish. I can't build specific targets using it, because my Makefile simply calls make in cmake's build directory.
Note that because the library is a sole dependency (and probably doesn't need to be build manually, and because I'm lazy) I omitted it in my Makefile.
BUILD_DIR := .build
.PHONY: all clean project-gui ${BUILD_DIR}/Makefile
all: project-gui project-test
clean:
#([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean && rm -r ${BUILD_DIR}) || echo Nothing to clean
project-gui: ${BUILD_DIR}/Makefile
#make -C ${BUILD_DIR} project-gui
#cp ${BUILD_DIR}/project-gui/project-gui $#
project-test: ${BUILD_DIR}/Makefile
#make -C ${BUILD_DIR} project-test
#cp ${BUILD_DIR}/project-test/project-test $#
${BUILD_DIR}/Makefile:
#[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR}
#[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CMAKE_OPTS} ..)
If it helps, here's my project structure (if this is "wrong" please tell me -- I'm still learning cmake):
project/
project/CMakeLists.txt
project/common.cmake
project/Makefile -- see Makefile above for this; should be replaced with something better, building libproject, project-gui, and project-test
project/libproject/
project/libproject/CMakeLists.txt
project/libproject/libproject.so -- after build
project/libproject/Makefile -- doesn't exist yet; should build libproject only
project/libproject/source/
project/libproject/include/
project/project-gui/
project/project-gui/CMakeLists.txt
project/project-gui/Makefile -- doesn't exist yet; should build libproject then project-gui
project/project-gui/source/
project/project-gui/include/
project/project-test/
project/project-test/CMakeLists.txt
project/project-test/Makefile -- doesn't exist yet; should build libproject then project-test
project/project-test/source/
project/project-test/include/
If you haven't caught on yet, I'm basically looking for a way to build the project and sub-projects as if cmake wasn't there: as if my project consisted of only Makefiles. Can this be done? Is the solution elegant, or messy? Should I be trying to do something else instead?
Thanks!
If cmake is generating the makefiles, you can simply include the generated makefile in the master makefile, eg
# makefile
all: # Default
include $GENERATED
$GENERATED:$CMAKEFILE
# Generate the makefile here`
The included files are generated then make is restarted with the new included files. The included files should detail the targets, etc.
You should be able to change the location of used files using the vpath directive, see e.g. the Gnu make manual,
vpath %.o project/.build
else the tedious way is to rewrite the rules making note of the necessary directory.
Ed:
Perhaps we shouldn't use a flat makefile.
Try something like:
# makefile
all: gui test
clean:
$(MAKE) -f $(GUI-MAKE) clean
$(MAKE) -f $(TEST-MAKE) clean
gui:$(GUI-MAKE)
$(MAKE) -f $(GUI-MAKE) all
$(GUI-MAKE):$(GUI-CMAKE)
# Generate
# Same for test
This should work if the $(MAKE) -f $(GUI-MAKE) all command works on the command line, and we've hidden cmake in the generating target. You would have to copy any other targets to the master makefile as well, and take care running make in parallel.
Propagating object files through should involve something like
%.o:$(GUI-MAKE)
$(MAKE) -f $(GUI-MAKE) $#
although you'll probably get errors trying to make test objects

Resources