Use make to only copy files that have changed - linux

I have a folder with a lot of header (.h) files and to install our library I need to copy these files to a system folder. However I would like to copy only the files that have changed. How can I do that using just make and cp, without having to use any other tool like rsync?

You could use constructs like this:
/path/to/system/header.h: /path/to/local/header.h
cp $^ $#
which copies the local header to the system header if the local version is newer.
If you have GNU make, like on Ubuntu, you can create fancy functions, like this.
It copies updated header files from directory SRCDIR to DSTDIR. Try it by running make all. It should only copy newer files and do nothing on a second run.
.DEFAULT_GOAL = all
SRCDIR = local
DSTDIR = system
HEADERS = $(shell cd $(SRCDIR); ls *.h)
# Define function; $(1) is the header file name.
define copyheader =
$(DSTDIR)/$(1): $(SRCDIR)/$(1)
cp $$^ $$#
endef
# Use function to create recipes for each header file.
$(foreach file,$(HEADERS),$(eval $(call copyheader,$(file))))
# Depend on all destination headers.
all: $(addprefix $(DSTDIR)/,$(HEADERS))

Related

Is there a way to define custom implicit GNU Make rules?

I'm often creating png files out of dot (graphviz format) files. The command to do so is the following:
$ dot my_graph.dot -o my_graph.png -Tpng
However, I would like to be able to have a shorter command format like $ make my_graph.dot to automatically generate my png file.
For the moment, I'm using a Makefile in which I've defined the following rule, but the recipe is only available in the directory containing the Makefile
%.eps: %.dot
dot $< -o $# -Teps
Is it possible to define custom implicit GNU Make recipes ? Which would allow the above recipe to be available system-wide
If not, what solution do you use to solve those kind of problem ?
Setup:
Fedora Linux with ZSH/Bash
You could define shell functions in your shell's startup files, e.g.
dotpng()
{
echo dot ${1%.dot}.dot -o ${1%.dot}.png -Tpng;
}
This function can be called like
dotpng my_graph.dot
or
dotpng my_graph
The code ${1%.dot}.dot strips .dot from the file name if present and appends it (again) to allow both my_graph.dot and my_graph as function argument.
Is it possible to define custom implicit GNU Make recipes ?
Not without modifying the source code of GNU Make.
If not, what solution do you use to solve those kind of problem ?
I wouldn't be a fan o modyfying the system globally, but you could do:
Create a file /usr/local/lib/make/myimplicitrules.make with the content
%.eps: %.dot
dot $< -o $# -Teps
Use include /usr/local/lib/make/myimplicitrules.make in your Makefile.
I would rather use a git submodule or similar to share common configuration between projects, rather than depending on global configuration. Depending on global environment will make your program hard to test and non-portable.
I would rather go with a shell function, something along:
mymake() {
make -f <(cat <<'EOF'
%.eps: %.dot
dot $< -o $# -Teps
EOF
) "$#"
}
mymake my_graph.dot
GNU Make lets you specify extra makefiles to read using the MAKEFILES
environment variable. Quoting from info '(make)MAKEFILES Variable':
the default goal is never taken from one of these makefiles (or any
makefile included by them) and it is not an error if the files listed
in 'MAKEFILES' are not found
if you are running 'make' without a specific makefile, a makefile
in 'MAKEFILES' can do useful things to help the built-in implicit
rules work better
As an example, with no makefile in the current directory and the
following .mk files in make's include path (e.g. via
MAKEFLAGS=--include-dir="$HOME"/.local/lib/make/) you can create
subdir gen/ and convert my_graph.dot or dot/my_graph.dot by
running:
MAKEFILES=dot.mk make gen/my_graph.png
To further save some typing it's tempting to add MAKEFILES=dot.mk
to a session environment but defining MAKEFILES in startup files
can make things completely nontransparent. For that reason I prefer
seeing MAKEFILES=… on the command line.
File: dot.mk
include common.mk
genDir ?= gen/
dotDir ?= dot/
dotFlags ?= $(if $(DEBUG),-v)
Tvariant ?= :cairo:cairo
vpath %.dot $(dotDir)
$(genDir)%.png $(genDir)%.svg $(genDir)%.eps : %.dot | $(genDir).
dot $(dotFlags) $< -o $# -T'$(patsubst .%,%,$(suffix $#))$(Tvariant)'
The included common.mk is where you'd store general definitions to
manage directory creation, diagnostics etc., e.g.
.PRECIOUS: %/. ## preempt 'unlink: ...: Is a directory'
%/. : ; $(if $(wildcard $#),,mkdir -p -- $(#D))
References:
?= = := … - info '(make)Reading Makefiles'
vpath - info '(make)Selective Search'
order-only prerequisites (e.g. | $(genDir).) - info '(make)Prerequisite Types'
.PRECIOUS - info '(make)Chained Rules'

Getting a portable (gnu) Makefile operate with pattern rules on files in subdirectories matching a regexp

I would like to use this Makefile both on Debian and Windows 10.
I have a set of measurements (and keep adding more) and the raw data files go into subdirectories called "measurement-12-Apr-2020" (with the date of the day I took the measurement). On those raw data files I run a series of post processing steps, each encapsulated in its own little tool, creating new output files and building on each other. Those different output files have distinct extensions: .raw for raw data files, .rot for coordinate rotations, .off for offset removal etc. I have pattern rules in my Makefile for those steps. For a few such steps I calculate special transformation matrices, that of course match just their set of data files. Those i call e.g. "transform.calibrate" or "transform.aligne"
So far the Makefile operated in just one directory and I moved the data files manually in and out of their directories.
Now I would like my top level Makefile with its pattern rules to operate on the data in the subdirectories.
How do i get it to look at the files in directories that match the "measurement-DATE" pattern? And how do i get the pattern rules to operate on one data set, using the local transformation files?
Here is my code with a recursive makefile. I would like a non-recursive makefile without the ugly
BIN := ${CURDIR}/../bin and half-good variable usage and content when the Makefile runs in the subdirectories. Furthermore i get an python error 9009 since i switched to the subdirs and the bin-directory (which is most likely related, but an other problem, really.).
ifdef OS
RM = del /Q
FixPath = $(subst /,\,$1)
COPY = copy
PYTHON = "c:\Users\Blah\AppData\Local\Programs\Python\Python37\python.exe"
else
ifeq ($(shell uname), Linux)
RM = rm -f
FixPath = $1
endif
COPY = cp
PYTHON = python
endif
.PHONY: test default
.DEFAULT_GOAL := default
# This is for running inside PyCharm
export PATH:=${CURDIR}/venv/bin:${PATH}
# file endings:
# raw
# calibrate file ending for transformation matrix
# cal calibrated data file
# ali alignement transformation
# rot rotated, aligned sensors
# off offset removed
# pha phase and
measurement_dirs := $(filter %/, $(wildcard messung-*/))
BIN := ../bin
DIRS_CMD = $(foreach subdir, $(measurement_dirs), make-rule/$(subdir))
# Makefiles = $(foreach subdir, $(measurements_dirs), $(subdir)Makefile )
default: transform.align transform.calibrate $(wildcard messung-*.pha)
all: $(DIRS_CMD)
#echo $(BIN)
transform.calibrate: calibrationsequence.raw
$(PYTHON) $(BIN)/calculateCalibration.py $<
%.cal: transform.calibrate %.raw
$(PYTHON) $(BIN)/applyCalibration.py $*.raw
transform.align: calibrationsequence.cal transform.calibrate
$(PYTHON) $(BIN)/calulateAlignement.py calibrationsequence.cal
%.rot: transform.align %.cal
$(PYTHON) $(BIN)/applyAlignment.py $*.cal
%.off: %.rot
$(PYTHON) $(BIN)/clearOffset.py $*.rot
%.pha: %.off
$(PYTHON) $(BIN)/demodulateSignals.py $*.off
test: test_%.py
$(PYTHON) pytest -v test
make-rule/%:
cp Makefile $* && cd $* && make
The heart of the problem is that two variables are involved and unknown beforehand: the names of the directories and the names of the raw files. Make can handle one variable easily, but struggles with two.
Suppose we have one directory, messung-12-Apr-2020, with three raw files alpha.raw, beta.raw and calibrationsequence.raw.
The rule is simple:
.PHONY: 12-Apr-2020
12-Apr-2020: messung-12-Apr-2020/apha.pha messung-12-Apr-2020/beta.pha messung-12-Apr-2020/calibrationsequence.pha
#echo $# done
If we do not know the names of the raw files beforehand, we can derive them:
RAW_FILES := $(wildcard messung-12-Apr-2020/*.raw)
PHA_FILES := $(patsubst %.raw,%.pha,$(RAW_FILES))
12-Apr-2020:$(PHA_FILES)
#echo $# done
If we do not know the name of the directory beforehand, we could use subst instead of patsubst and put everything into a pattern rule:
TARGETS := 12-Apr-2020
.SECONDEXPANSION:
$(TARGETS): %: $$(subst .raw,.pha,$$(wildcard messung-%/*.raw))
#echo $# done
(Note the use of $$.) This is safe as long as there is no chance of ".raw" embedded in a file name. There is a safer, more rigorous approach, but it is more complicated; if you need it, let me know in a comment and I will post it.
Now to generate the list of targets:
TARGETS := $(patsubst messung-%,%,$(wildcard messung-*))
.PHONY: all $(TARGETS)
all: $(TARGETS)
and modify the other pattern rules to be executed from the master directory:
%.pha: %.off
cd $(dir $*); $(PYTHON) $(BIN)/demodulateSignals.py $(notdir $*).off
(Clumsy, but effective.) It should be clear how to modify the pattern rules for %.off, %.rot, %.cal, %/transform.calibrate and %/transform.align the same way.

How to overwrite linux system files into the yocto filesystem?

I am new, yocto build at imx6q embedded system.
I want to overwrite linux system files after do_rootfs. For example, target system files are below.
/etc/network/interface
/etc/issue
/etc/init.d/rcS
/home/root/mytest.sh
so, i made custom layer and custom recipe.
helloworld binary is copy ok.
but, do_mytask function is not called.
what's wrong with my code?
or any other method for my purpose.
#
# This file was derived from the 'Hello World!' example recipe in the
# Yocto Project Development Manual.
#
SUMMARY = "Simple helloworld application"
SECTION = "examples"
LICENSE = "MIT"
LIC_FILES_CHKSUM = "file://${COMMON_LICENSE_DIR}/MIT;md5=0835ade698e0bcf8506ecda2f7b4f302"
SRC_URI = "file://helloworld.c"
S = "${WORKDIR}"
do_compile() {
${CC} helloworld.c -o helloworld
}
do_install() {
install -d ${D}${bindir}
install -m 0755 helloworld ${D}${bindir}
}
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
SRC_URI += " \
file://interfaces \
file://issue \
file://mytest.sh \
"
addtask mytask after do_rootfs before do_image
do_mytask() {
install -d ${D}/etc/network
cp -af ${WORKDIR}/interfaces ${D}/etc/network/interfaces
cp -af ${WORKDIR}/issue ${D}/etc/issue
}
You'll need to extend the recipes that provide the files you want to replace.
Using /etc/network/interfaces as an example, the first step is to figure out which recipe installs that file.
From the bitbake prompt:
$ oe-pkgdata-util find-path /etc/network/interfaces
init-ifupdown: /etc/network/interfaces
So this tells us that /etc/network/interfaces is installed by the init-ifupdown receipe.
A file search shows that init-ifupdown is part of poky:
$ find . -name init-ifupdown*.bb
./poky/meta/recipes-core/init-ifupdown/init-ifupdown_1.0.bb
Now, since you need to modify the output of init-ifupdown, you'll need to extend init-ifupdown by creating a similarly named .bbappend in your own layer.
You might create the new .bbappend at
my-layer/receipes-core/init-ifupdown/init-ifupdown_%.bbappend
The % is a wildcard that ensures the .bbappend will apply to all future versions of the init-ifupdown recipe, which is probably what you want.
Place your custom interfaces file in a folder below the .bbappend:
my-layer/receipes-core/init-ifupdown/files/interfaces
The .bbappend then only needs to contain a single line to enable bitbake to pick up the new interfaces file:
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
Finally, repeat the above with each system file you'd like to replace.
It depends on the file to modify. For example, if you search 'interfaces' in poky directories, you'll find it in 'meta/recipes-core/init-ifupdown/init-ifupdown-${PV}/'. You just need to create a recipe named init-ifupdown-${PV}.bbappend in your meta, recreating the path seen in poky (recipes-core/init-ifupdown/). This recipe can contain a single line :
FILESEXTRAPATHS_prepend := "${THISDIR}/files:"
Then you create a 'files' folder with the 'interfaces' file you want to have.
For 'issue', like others found in the /etc directory (profile, fstab, ...), it's the same procedure, with the sources in poky/meta/recipes-core/base-files/.
For init.d scripts, use the 'update-rc' class.
You recipe is not "image recipe" (and it shouldn't be for hello world) thus you cannot use tasks do_rootfs and do_image in this case. A bit of clarification: image recipe is .bb file that you use to build image with bitbake or devtool (in your case some containing imx6q, you can find them with bitbake-layers show-recipes "*-image-*").
It looks like you are looking really is a way to override do_install of some recipe that installs that mentioned files. Then find what recipe installs those files and create bbappend file in your top layer. This bbappend file may contain do_install_append task where you can place your install <file> <dir> lines (note, using cp as not recommended, everything should be done with install tool).
Adding an extra comment based on Carsten Hansen original answer for folks working with Xilinx/Petalinux.
Under Petalinux environment we don't really have the command: oe-pkgdata-util, so the strategy is to do a search in the Xilinx SDK folder. You might have it installed on Linux under /opt according to the documentation. If you do a:
grep -r syslog-startup.conf .
you will see busybox recipe being the one that does the installation of the syslog-startup.conf.
You can create the override recipe called busybox_%.bbappend under:
../project-spec/meta-user/recipes-core/busybox/
Put the modified syslog-startup.conf file under:
../project-spec/meta-user/recipes-core/busybox/files/syslog-startup.conf
Rebuild via petalinux-build. You can also force the creation of the rootfs via petalinux-build -c rootfs and the system should populate your new file.

Including patches to Build Root

I tried to include my custom helloword patch to build root.
in
make menuconfig
I have added global patch directory /home/Downloads/buildroot/buildroot-2017.11/patches
and I place my patch files inside the below directory
(/home/Downloads/buildroot/buildroot-2017.11/patches/packagename/version/patch).
I referred this link and this link
After make command the patch is not getting applied in my source directory, the source is getting extracted to the output/build directory from the .tar fle.
please suggest a solution..
Config.in
config BR2_PACKAGE_HELLOWORLD
bool "helloworld"
help
Hello World package says hello world to you
see http://helloworld.com for more on this software
helloworld.mk
HELLOWORLD_VERSION = 1.0.0
HELLOWORLD_SOURCE = helloworld-1.1.tar.gz
HELLOWORLD_PATCH = 18-helloworld-testing.patch
HELLOWORLD_SITE_METHOD = local
define HELLOWORLD_BUILD_CMDS
$(MAKE) $(TARGET_CONFIGURE_OPTS) -C $(#D)
endef
define HELLOWORLD_INSTALL_TARGET_CMDS
$(INSTALL) -D -m 0755 $(#D)/helloworld $(TARGET_DIR)/usr/bin/helloworld
$(INSTALL) -D -m 0755 $(#D)/helloworld-init $(TARGET_DIR)/etc/init.d/S90helloworld
endef
$(eval $(generic-package))
With the local _SITE_METHOD, patches are not applied. local is when you want to use the files directly from their source directory. With the local _SITE_METHOD, the directory specified in HELLOWORLD_SITE will be copied to the build directory, no patches are applied, the _SOURCE is not used.
However, since you don't specify HELLOWORLD_SITE, you trigger a corner case that causes it to behave like the file _SITE_METHOD (which is the one you actually want). Buildroot should give an error for this case. A patch is pending for this.
Unfortunately, that doesn't explain why the patches don't get applied.

Header file not found during compilation with make (Linux)

I am getting the following error during make:
In file included from modGPRS.c:25:
../inc/intModGPRS.h:33:21: error: datapkt.h: No such file or directory
The directory structure is as follows:
datapkt.h is placed at main_proj/libs/ipsec/itf.
libs folder has a Makefile which is as follows:
include $(BUILD_TOP)/build_control/stream/config.mk
SUBDIRS = tracing config stats srandom
SUBDIRS_$(B_HAS_EEPROM) += eeprom
SUBDIRS_$(B_LIBARCHIVE) += libarchive
ifeq ($(B_PLATFORM_openat),y)
SUBDIRS += openat openssl asn1c mib zlib diff ipsec
else
SUBDIRS += iniparser daemon ipsec
endif
stats_needs = config
include $(BUILD_TOP)/build_control/stream/subdirs.mk
Makefile for ipsec is as follows:
SDIRS += src itf
TOP?=..
RECURSIVE_MAKE= [ -n "$(SDIRS)" ] && for i in $(SDIRS) ; do \
(cd $$i && echo "making $$target in $(DIR)/$$i..." && \
$(MAKE) -e TOP=$(TOP)/.. $$target INCLUDES='$(INCLUDES)') || exit 1; \
done;
subdirs:
#target=all; $(RECURSIVE_MAKE)
all: subdirs -I /itf
include $(BUILD_TOP)/build_control/stream/subdirs.mk
Also subdirs.mk is as follows:
# This is a stand-alone file to distribute targets to
# sub-directories. Include this file alone.
# Make bug: It loses track of if/endif over a $(eval) call.
ifndef __subdirs_include
__subdirs_include = yes
# This only works for the standard targets defined in $(TARGETS)
# in utils.mk. However this list can be extended with +=.
install:: install-hdrs
include $(BUILD_TOP)/build_control/stream/utils.mk
include $(BUILD_TOP)/build_control/stream/platform.mk
# This creates a recursion rule for each pair of target and subdirectory.
# The target for doing T in directory D is named T+D.
# If there is a "$(D_needs) = subdirs" then the subdirs become prerequisites
# of D.
define __target_subdir
.PHONY:: $(1)+$(2)
$(1)+$(2) :: $(3); +$(MAKE) -C $(2) $(1)
endef
$(foreach t,$(TARGETS),\
$(foreach d,$(strip $(SUBDIRS) $(SUBDIRS_y)),\
$(eval $(call __target_subdir,$(t),$(d),$(patsubst %,$(t)+%,$($(d)_needs))))))
$(foreach t,$(TARGETS),\
$(foreach d,$(strip $(SUBDIRS) $(SUBDIRS_y)),$(eval $(t)::$(t)+$(d))))
endif # __subdirs_include
could someone please help me figure out, how to solve this issue of the header file: datapkt.h? Please let me know if any other details are required.
Thanks
Sunny
The error message is from your compiler. It is saying that the file modGPRS.c (in whatever directory it is in, call it A) has included a file A/../inc/intModGPRS.h, which is itself trying to include a file called datapkt.h, which cannot be found. This is either because your makefiles are not properly telling the compiler where the file datapkt.h is, or (more likely) you have not installed a prerequisite library.
Make sure you have installed everything that needs to be installed before trying to build whatever it is that you're trying to build. Without at least telling me what it is you're trying to install I can't help you further.

Resources