I have a data directory which I would like automake to generate install and uninstall targets for. Essentially, I just want to copy this directory verbatim to the DATA directory, Normally, I might list all the files individually, like
dist_whatever_DATA=dir/subdir/filea ...
But the problem arises when my directory structure looks like this
*root
*subdir
*~10 files
*subdir
*~10 files
*subdir
*~700 files
*subdir
...
~20 subdirs
I just cannot list all 1000+ files included as part of my Makefile.am. That would be ridiculous.
I need to preserve the directory structure as well. I should note that this data is not generated at all by the build process, and is actually largely short audio recordings. So it's not like I would want automake to "check" that every file I want to install has actually been created, as they're either there or not, and whatever file is there, I know I want it to be installed, and whatever file is not, should not be installed. I know that this is the justification used in other places to not do wildcard instsalls, but all the possible reasons don't apply here.
I would use a script to generate a Makefile fragment that lists all the files:
echo 'subdir_files =' > subfiles.mk
find subdir -type f -print | sed 's/^/ /;$q;s/$/ \\/' >> subfiles.mk
and then include this subfiles.mk from your main Makefile.am:
include $(srcdir)/subfiles.mk
nobase_dist_pkgdata_DATA = $(subdir_files)
A second option is to EXTRA_DIST = subdir, and then to write custom install-data-local and uninstall-local rules.
The problem here is that EXTRA_DIST = subdir will distributes all files in subdir/, including backup files, configuration files (e.g. from your VCS), and other things you would not want to distribute.
Using a script as above let you filter the files you really want to distribute.
I've found that installing hundreds of files separately makes for a tormentingly long invocation of make install. I had a similar case where I wanted to install hundreds of files, preserving the directory structure, and I did not want to change my Makefile.am every time a file was added to or removed from the collection.
I included a LZMA archive of the files in my distribution, and made automake rules like so:
GIANTARCHIVE = My_big_archive.tar.lz
dist_pkgdata_DATA = $(GIANTARCHIVE)
install-data-hook:
cd $(DESTDIR)$(pkgdatadir); \
cat $(GIANTARCHIVE) | unlzma | $(TAR) --list > uninstall_manifest.txt; \
cat $(GIANTARCHIVE) | unlzma | $(TAR) --no-same-owner --extract; \
rm --force $(GIANTARCHIVE); \
cat uninstall_manifest.txt | sed --expression='s/^\|$$/"/g' | xargs chmod a=rX,u+w
uninstall-local:
cd $(DESTDIR)$(pkgdatadir); \
cat uninstall_manifest.txt | sed --expression='s/ /\\ /g' | xargs rm --force; \
rm --force uninstall_manifest.txt
This way, automake installs My_big_archive.tar.lz in the $(pkgdata) directory, and extracts it there, making a list of all the files that were in it, so it can uninstall them later. This also runs much faster than listing each file as an install target, even if you were to autogenerate that list.
I would write a script (either as a separate shell script, or in the Makefile.am), that is run as part of the install-data-hook target.
Related
I have few files in sub directories, all the files are just text files like faq, user guides.There are no c/cpp src code
in it. Following is the file and directory structure.
scr
|_Makefile #Top level Makefile
|_other_dirs
|_some_other_dirs
|_mydir
|_Makefile #Makefile of mydir, need to put some code here
|_dir1
| |_textfile0
| |_textfile1
|_dir2
|_textfile2
|_textfile3
Question, How can I tar the contents of dir1 and dir2 into one tar ball? I tried searching over internet about the Makefile and how to use it to create the take ball from top Makefile but no success yet. I am not very familiar with Makefiles, any starting point will be appreciated. Thanks.
Following is my novice attempt to have a very basic Makefile:
-->cat Makefile
mydir.tgz : *
tar -zcvf mydir.tgz mydir/
-->make
Makefile:1: *** missing separator. Stop.
Idea is to run top Makefile and have tar file generated for mydir.
You can add all files and directories in mydir recursively as a prerequisite of mydir.tgz. That way, your tar file will be executed if, and only if, a change occurs somewhere under mydir. For example like this:
mydir.tgz: $(shell find mydir)
tar -zcvf mydir.tgz mydir
The line with the tar command should start with at TAB.
Most of the mechanisms of this answer are also described in this SO question, but it seemed to make sense to me to add it here to concisely answer your specific question.
I have a makefile consisting of several targets with some dependencies.
a small structure looks like following
pgdynamic_setup:
cd $(PGDYNAMICDIR); . /opt/Modules/init/sh; module load <tool_name>; totem2 -lmwait $(PGDYNAMIC_APACHE_LN) $(BATCH_NOBATCH) dynamic_setup.tcl | tee -i ./logs/$#.log
pgdynamic_current: pgdynamic_setup
cd $(PGDYNAMICDIR); . /opt/Modules/init/sh; module load <tool_name>; <tool_name> dynamic_current.tcl | tee -i ./logs/$#.log
pgdynamic_cdev: pgdynamic_setup
cd $(PGDYNAMICDIR); . /opt/Modules/init/sh; module load <tool_name>; <tool_name> dynamic_cdev.tcl | tee -i ./logs/$#.log
pgdynamic_tool: pgdynamic_current
cd $(PGDYNAMICDIR); . /opt/Modules/init/sh; module load <tool_name>; <tool_name> dynamic.tcl | tee -i ./logs/$#.log
I don't have too much experience writing Makefiles. The problem is, when I run make pgdynamic_setup, and then make pgdynamic_current make executes both targets (pgdynamic_setup and pgdynamic_current). But as I have explicitly run pgdynamic_setup I would expect that make only executes the target pgdynamic_current.
This is not a MWE. when I try the same concept with some touch, cat commands it simply works as expected. I guess there is something wrong in this structure. could anybody help me on a structure basis as I cannot provide a working MWE. sorry and thanks in advance.
Make works by comparing timestamps of files that exist on your computer. It doesn't maintain some internal database of what rules have been run: it compares the timestamps of the prerequisite files with the timestamps of the target files.
If you write this makefile using touch, you're creating the targets as files on the local disk, so make can see which rules have been run and which have not.
In your "real" example, you aren't creating any files (your rules don't make files named pgdynamic_tool, pgdynamic_current, ec.) and so make has no idea when these rules were last run.
If you want make to skip the rules that have been run already, you have to create files with those names on the disk when they're run so that make knows about it. You can use touch $# to do this.
ETA you want something like this:
pgdynamic_setup:
cd $(PGDYNAMICDIR); . /opt/Modules/init/sh; module load <tool_name>; totem2 -lmwait $(PGDYNAMIC_APACHE_LN) $(BATCH_NOBATCH) dynamic_setup.tcl | tee -i ./logs/$#.log
touch $#
Say there are a bunch of (e.g. nearly 200) modules that all depend on a core module. All are using Autotools.
The core module installs a core.m4 file which the dependents already use for various things.
All the dependents also have some lines in their install-data-local rule to generate some scripts and install them, e.g.
core_stuffdir=$(prefix)/share/core/stuff/
install-data-local:
generate-stuff stuff.xml
test -d $(DESTDIR)$(core_stuffdir) || mkdir $(DESTDIR)$(core_stuffdir)
stuff=`xmllint --xpath '//stuff[#install="yes"]/#name' stuff.xml`; \
$(INSTALL_DATA) $$stuff $(DESTDIR)$(core_stuffdir); \
rm $$stuff
…
$(INSTALL_DATA) other-module-specific-stuff …
…
I would like to remove those five lines which are currently redundantly duplicated over ~200 files, and instead define the lines in the core.m4. The dependents should be able to say something like SOMEVAR: somevalue (or something similarly short, at worst a one-line thing in install-data-local) and have those lines executed during make install.
Is there a nice way to do define these lines in core.m4 and make them available to Makefile.am? I can't find any similar examples on the net.
The only solution I can think of now is that the m4 spits out a shell script that I can call from install-data-local, but I'm not sure that's the best (or most autotoolish) way.
Alternatively, is there a simple way to distribute an automake fragment.am file from my core module? (This seems to be the way e.g. Python compilation rules are defined.)
After some digging, I found
http://thread.gmane.org/gmane.comp.sysutils.automake.general/5704/focus=5708
which has a solution to a similar problem (I couldn't get the
AC_CONFIG_FILES solution mentioned there to work).
So core.m4 now defines CORE_MKINCLUDE:
AC_DEFUN([CORE_MKINCLUDE],
[
AC_SUBST_FILE(core_include)
core_include=$srcdir/core_include.am
cat >$srcdir/core_include.am <<EOF
core_stuffdir=\$(prefix)/share/core/stuff/
install-stuff:
generate-stuff stuff.xml
test -d \$(DESTDIR)\$(core_stuffdir) || mkdir \$(DESTDIR)\$(core_stuffdir)
stuff=\`xmllint --xpath '//stuff#<:##install="yes"#:>#/#name' stuff.xml`; \\
\$(INSTALL_DATA) \$\$stuff \$(DESTDIR)\$(core_stuffdir); \\
rm \$\$stuff
EOF
])
Ie. the goal is now printed to the file core_include.am, and has its
own name. Each module's configure.ac calls CORE_MKINCLUDE, and each
Makefile.am just has
#core_include#
install-data-local: install-stuff
An improvement at least.
Is it possible to tell make to only build a target if it's sources md5 checksum has changed (instead of the edit time)?
I'm using make to compile my .tex files and I need to prevent it from building everything twice all the time.
I've tried using Scons, but I feel this isn't adaptable to other needs I have.
No, this is not supported by Make — as you've found out, support for this feature is one of the reasons why tools like Scons exist.
I found a manual recipe for GNU make, though. Maybe you can use that as a work around.
I found 3 ways: From simply
Using temporary md5-files over an
elegant but unreadable hack to
patching GNU Make yourself
(from patchy but simple to clean but hard to realize)
Maybe my scons latex and org-mode recipe helps you:
## I need a couple of special builders for my projects
# the $SOURCE replacement only uses the first source file. $SOURCES gives all.
# specifying all source files makes it possible to rerun the build if a single source file changed.
orgexportpdf = 'emacs --batch --visit "$SOURCE" --funcall org-export-as-pdf'
pyxplot = 'pyxplot $SOURCE'
# pdflatex is quite dirty. I directly clean up after it with rm.
pdflatex = 'pdflatex $SOURCE -o $TARGET; rm -f *_flymake* flymake* *.log *.out *.toc *.aux *.snm *.nav *.vrb'
# build the PhD thesis from emacs org-mode.
Command("doktorarbeit.pdf", "doktorarbeit.org",
orgexportpdf)
# create plots
Command(["images/comp-t3-s07-tem-boas.png",
"images/comp-t3-s07-tem-bona.png"],
["nee-comp.pyx",
"nee-comp.txt"],
pyxplot)
# build my sink.pdf
Command("sink.pdf",
["sink.tex",
"images/comp-t3-s07-tem-boas.png",
"images/comp-t3-s07-tem-bona.png",
"images/bona-marble.png",
"images/boas-marble.png"],
pdflatex)
# My editors leave tempfiles around. I want them gone after a build clean. This is not yet supported!
tempfiles = Glob('*~') + Glob('#*#') + Glob('*.bak')
# using this here would run the cleaning on every run.
#Command("clean", [], Delete(tempfiles))
It is the counterpart for my Makefile:
all: doktorarbeit.pdf sink.pdf
sink.pdf : sink.tex images/comp-t3-s07-tem-boas.png images/comp-t3-s07-tem-bona.png images/bona-marble.png images/boas-marble.png
pdflatex sink.tex
rm -f *_flymake* flymake* *.log *.out *.toc *.aux *.snm *.nav *.vrb # kill litter
comp-t3-s07-tem-boas.png comp-t3-s07-tem-bona.png : nee-comp.pyx nee-comp.txt
pyxplot nee-comp.pyx
# http://www.reddit.com/r/emacs/comments/dy9yt/anyone_know_of_a_script_that_i_can_feed_an/
# http://blog.nguyenvq.com/2010/10/30/bash-batch-script-to-convert-org-mode-file-to-html/comment-page-1/#comment-27013
doktorarbeit.pdf : doktorarbeit.org
emacs --batch --visit "doktorarbeit.org" --funcall org-export-as-pdf
# this is not what clean is intended to do, but I do it anyway.
clean :
rm -f \#* *~ *.bak # kill editor backups
# alternatively run scons. Should I switch to SCons, just put this in all :)
sconsrun : scons
python scons/bootstrap.py -Q
scons :
hg clone https://bitbucket.org/ArneBab/scons
I have a list of file paths in a variable. I'd like to copy each file in this list to a new location. The problem is that I'm very new to makefiles and I'm struggling to get anything working. My attempt has culminated at the following, although not working (and probably totally wrong) I hope it illustrates what I'm trying to do.
FILES = a/b/file c/d/file e/.../file etc...
copyfiles:
for file in $(FILES); do \
cp $$file newDir/$(notdir $$file); \
done
You could do
FILES = a/b/file c/d/file e/.../file etc...
copyfiles:
cp $(FILES) newDir
I tried it, and it works.
Remember, globbing is done by the shell, not by the commands. cp takes a list of files as arguments, and copies all of them to the location specified by the last argument. When you type cp *.cpp all the cp program sees as its arguments are the files in the current directory that end in .cpp.