I would like to merge C source files as I was doing with CIL and the cilly script. Does Frama-c provide this scripting functionality ?
Frama-C will link together all the files that are given on its command line, i.e. if you do
frama-c file1.c file2.c -print
Frama-C will pretty-print the content of file1.c and file2.c, after having taken care that there's no incoherence between them (e.g. a function f declared with incompatible parameter types).
Related
The problem
Consider the following recipe:
a: b
<create a>
Maybe it's correct. But if b imports another program c,
then it's not. It should instead say this:
a: b c
<create a>
And if c depends on d, it should say this:
a: b c d
<create a>
And any time c changes what it imports,
any output that depends on b
needs its recipe updated in the makefile.
That's tedious. It's also dangerous,
because it's easy to miss a recipe that needed updating.
What would be better
is to only have to say once what other source files a given source file depends on,
rather than each time it appears in any recipe's prerequisites.
That is, the Makefile should be doing the recursion, not I.
(Even better would be if I had to say zero times what the source file depends on, instead generating that information automatically from the code. I wonder if such a solution exists?)
I have an awkward solution.
Here's a (extremely) minimal example:
https://github.com/JeffreyBenjaminBrown/makefile-import-aware/
Here's the Makefile (everything else in the repo is just empty files or documentation):
.no_younger_than/lib/a: \
code/lib/a
install -D /dev/null .no_younger_than/lib/a
.no_younger_than/b: \
code/b \
.no_younger_than/lib/a
install -D /dev/null .no_younger_than/b
c: .no_younger_than/b
echo "yes" > c
Those install directives create a filetree parallel to the code,
which contains an empty "evidence" file corresponding to each source file.
The makefile creates such evidence each time it runs.
If the timestamp on an evidence file is T,
that means the file it corresponds to was not modified any later than T.
This solution does everything that I want,
but I dread having to explain it to someone else.
I'm hoping there exists prior art that's already been documented,
so I can avoid said explanation.
What's the difference between:
ar -x liba.a
ar -x libb.a
ar rcs libab.a *.o
and
ar rcs libab.a liba.a libb.a
Are they really doing the same task?
Unless you're using a version of ar that I don't know about, the effects of the two sequences of commands are quite different — though both end up creating a file libab.a.
The first sequence extracts all the (object) files from liba.a into the current directory, then all the files from libb.a (any name collisions mean the file from libb.a will survive), and then all the object files that are now in the directory (possibly including ones that were in neither liba.a nor libb.a) are archived in libab.a.
The second sequence creates an archive that itself contains two files: liba.a and libb.a. This is legal and feasible, but the resulting file isn't useful in linking programs. The linker doesn't look at nested archives; it will simply find no object files that supply any symbols (since neither liba.a nor libb.a is an object file), so the library will effectively be unused — though you'll not get an error from attempting to use it.
It is more likely that the first sequence of commands is useful than the second.
Here's some pseudocode for what I want my makefile to do:
if (A doesn't exist) or (B is newer than A):
rm -rf A
create an empty A
parallel_for X in (a large set of files):
if (X is newer than A):
update A using the contents of X
In the above pseudocode, A is an SQLite database, B is a C header file, and each of the files in the "large set of files" is a C source file.
Basically, if I only modify one of the C source files, I just want the database to be quickly updated rather than rebuilding the entire database from scratch.
Is this type of problem solvable directly in GNU make, or am I going to have to resort to using a script?
Thanks in advance!
Something like this ought to work:
A:: B
-rm -f $#
create_A $#
A:: $(all_X)
update_A_from_Xes $# $?
$? expands to the subset of $(all_X) that are newer than A (see the "Automatic Variables section of the GNU Make manual for more details). Therefore, update_A_from_Xes must update its first argument with respect to all of the subsequent arguments; it will only be invoked once.
The double colons tell Make that the commands to run to update A are different when it's out of date with respect to B than when it's out of date with respect to the Xes. I am not sure whether both sets of commands will get run in the case that it is out of date with respect to both; if they do both get run, the A:: B rules will get run first.
I would like to have a makefile like this:
cudaLib :
# Create shared library with nvcc
ocelotLib :
# Create shared library for gpuocelot
build-cuda : cudaLib
make build
build-ocelot : ocelotLib
make build
build :
# build and link with the shared library
I.e. the *Lib tasks create a library that runs cuda directly on the device, or on gpuocelot respectively.
For both build tasks I need to run the same build steps, only creating the library differs.
Is there an alternative to running make directly?
make build
Kind of a post-requisite?
Note: This answer focuses on the aspect of a robust recursive invocation of a different target in a given makefile.
To complement Jack Kelly's helpful answer, here's a GNU makefile snippet that demonstrates the use of $(MAKE) to robustly invoke a different target in the same makefile (ensuring that the same make binary is called, and that the same makefile is targeted):
# Determine this makefile's path.
# Be sure to place this BEFORE `include` directives, if any.
THIS_FILE := $(lastword $(MAKEFILE_LIST))
target:
#echo $# # print target name
#$(MAKE) -f $(THIS_FILE) other-target # invoke other target
other-target:
#echo $# # print target name
Output:
$ make target
target
other-target
Using $(lastword $(MAKEFILE_LIST)) and -f ... ensures that the $(MAKE) command uses the same makefile, even if that makefile was passed with an explicit path (-f ...) when make was originally invoked.
Note: While GNU make does have features for recursive invocations - for instance, variable $(MAKE) specifically exists to enable them - their focus is on invoking subordinate makefiles, not on calling a different target in the same makefile.
That said, even though the workaround above is somewhat cumbersome and obscure, it does use regular features and should be robust.
Here is the link to the manual section covering recursive invocations ("sub-makes"):
Recursive Use of make
Most versions of make set a variable $(MAKE) that you can use for recursive invocations.
As you have written it, the build target will need to do something different depending on whether you have just done an ocelot or cuda build. That's another way of saying you have to parameterise build in some way. I suggest separate build targets (much like you already have), with associated variables. Something like:
build-cuda: cudaLib
build-ocelot: ocelotLib
build-cuda build-ocelot:
shell commands
which invoke ${opts-$#}
On the command-line you type make build-cuda (say). Make first builds cudaLib, then it carries out the recipe for build-cuda. It expands the macros before calling the shell. $# in this case is build-cuda, thus ${opts-$#} is first expanded to ${opts-build-cuda}. Make now goes on to expand ${opts-build-cuda}. You will have defined opts-build-cuda (and of course its sister opts-build-ocelot) elsewhere in the makefile.
P.S. Since build-cuda et. al. are not real files, you had better tell make this (.PHONY: build-cuda).
I have a number of C/C++ project files. I'd like to know the full list of preprocessor symbols used by the files. Is there a flag to gcc, or is there some tool I can use to get this list.
Optionally, if the tool also told me the list of symbols defined by the file, that would be great.
Use gcc -E -dM <file_list> - preprocess, then output #defines.
My gcc is a tad rusty, so I'm not sure whether or not you explicitly need the -E, but try both?
For further reference, see this