How does sconstruct receive input? - makefile

I want to use Sconstruct instead of Makefile. But I found that many situations in the Makefile are difficult to implement in Sconstruct.
For example,
I have three .c files, a.c, b.c, and c.c. I want to decide which file to compile into the final file based on the input. In Makefile I can use make a, make b, make c to achieve. But in sconstruct, scons e decides which statement to execute based on the final target file. Is there a way to decide which statement to execute based on the source file or a lable?
Sometimes in the Makefile, I want to compile multiple files at once, but not all files. In the Makefile, I can write the compilation of multiple files under one label. Is there such a method in Sconstruct?
I found a lot of documents about sconstruct on the Internet, but basically every document introduces the most basic commands.

Possibly not understanding all of the question, but SCons, builds the targets you ask it to on the command line, like Make does. If you don't give it any, it builds the default targets, which you yourself can define through Default() calls. If neither, then it builds ".", which means all of the targets discovered underneath the directory of the SConstruct.
Targets don't have to be the name of a file to build, you can use the Alias() function to assign a name that will work as a build target. An alias can refer to several targets if you wish, which seems to be your second question.
Feel free to hop onto the SCons Discord channel if you want to chat more interactively (see https://scons.org/contact.html for links)

Related

I'm seeing occasional build failure due to auto generated files (automake). How do I create dependencies between autogenerated files?

I have been trying to debug a makefile.am that occasionally causes a build failure in make. In this file, the sources are auto generated .c files and the headers are auto generated .h files.
..._SOURCES = #buildDirectory#/x.c
#buildDirectory#/y.c
#buildDirectory#/z.c
..._HEADERS = #buildDirectory#/x.h
#buildDirectory#/y.h
#buildDirectory#/z.h
The failure looks like this
<failedproto>.proto: "symbol1" is not defined.
<failedproto>.proto: "symbol2" is not defined.
<failedproto>.proto: "symbol3" is not defined.
...
<failedproto>.proto: warning: Import <failedproto>.proto but not used.
make: *** [<failedproto>.c] Error 1
make: *** Waiting for unfinished jobs....
All of these symbols appear in the a corresponding .h. This leads me to think that the .c is being generated before the .h, and its just a straight race. I have added both ..._SOURCES and _HEADERS to BUILT_SOURCES, but I still see the failure. So my next instinct is to create a dependency for the .c on the .h. How do I do this, since they are both auto generated? Also, any alternative solutions would be welcome too.
Hopefully my formatting is not confusing.
Edit with some more detail:
These files are being auto generated by the protoc-c compiler: https://github.com/protobuf-c/protobuf-c
The protoc-c takes these .proto files and generates .pb-c.c and .pb-c.h files, making me think that these two are not dependent after all. Some in house code is also run, which generates other .proto files, I will call them nameX.proto and nameY.proto, which in turn generate nameX.pb-c.c/nameX.pb-c.h and nameY.pb-c.c/nameY.pb-c.h. A more accurate example of the Makefile.am is like this:
..._SOURCES = #buildDirectory#/name.pb-c.c
#buildDirectory#/nameX.pb-c.c
#buildDirectory#/nameY.pb-c.c
..._HEADERS = #buildDirectory#/name.pb-c.h
#buildDirectory#/nameX.pb-c.h
#buildDirectory#/nameY.pb-c.h
I have been trying to track these dependencies, and I will try and describe what conclusions I have come to. nameX.pb-c.c includes its corresponding header nameX.pb-c.h. That header includes nameY.pb-c.h, making me think that nameX.proto is being compiled into nameX.pb-c.c/nameX.pb-c.h before nameY.proto can be compiled. Since there is an include relationship between nameX.pb-c.h and nameY.pb-c.h, the build fails because nameX.pb-c.h needs nameY.pb-c.h. This leads me to two rules I've been suspicious about from the start. These rules are generalized like this:
$(OUT_DIRECTORY)/%nameX.proto:$(SRC_DIRECTORY)/name.proto $(SRC_DIRECTORY)/nameY.proto
command $(OUT_DIRECTORY) $(FLAGS) $<
$(OUT_DIRECTORY)/%nameX.proto:$(SRC_DIRECTORY)/name.proto
command $(OUT_DIRECTORY) $(FLAGS) $<
Could this be an issue? What is stopping the second rule from being run if it truly needs the first rule?
To make matters worse, many of the .proto files are intermediate files (they are generated then discarded throughout the build) so I cannot look at them to see what they look like.
It's very unusual to use #...# replacements throughout your makefile like this. Normally you would assign the replacement once, to a make variable, then use the variable instead (in addition to being "nicer to read", this allows someone to override this value on the make command line if they want to):
BUILDDIR = #buildDirectory#
..._SOURCES = $(BUILDDIR)/x.c
$(BUILDDIR)/y.c
$(BUILDDIR)/z.c
..._HEADERS = $(BUILDDIR)/x.h
$(BUILDDIR)/y.h
$(BUILDDIR)/z.h
Also, it seems likely to me that there are standard automake variables that might already cover this value; if so it's better to use the standard ones than invent new ones... but obviously there's no way to know that without knowing more about your environment.
Anyway, for your question we need to know more about this autogeneration operation. What do your rules for autogenerating look like now? Is it really the case that the generation of the .c file can't be done until the .h file is generated? That's unusual.
If you list the output file, the input files, and the command needed then it's pretty simple to write a correct rule.

How can I add built-in rules to make?

Make(1) has built-in rules, such that for simple tasks you don't need a makefile at all. I can type make prog and if the current directory has a prog.c, make will do something useful.
I have a number of rules like this (e.g., how to make .pdf from .html) that apply in many projects. If I have a makefile in a directory, I can simply include my rules from a file. Is there a way to tell make to use this file always? Like a dot file that make would always include before doing anything else.
Make's rules are truly built-in, not read from a file. This has advantages (the entirety of make is one executable and you can copy it and install it anywhere and get identical behavior) and disadvantages (you can't modify the default rules without modifying the source code and recompiling--if you want to do that it's easy to do, though: see the default.c file in the sources).
You can specify an extra makefile (or makefiles) that should be parsed before the usual ones using an environment variable, though, so you can create a makefile with some extra rules, then (in your ~/.bashrc or whatever) set the MAKEFILES environment variable to the name of that file (or files) containing these extra rules (don't forget to export it).
Now every make invocation will load these rules as well.
You may discover, though, that this isn't quite what you'd hoped, because it could cause other makefiles to fail or act in bizarre ways (for example if you download open source packages and want to build them locally, etc.) If you do this just remember you did it, so in a few months if you run into issues you'll remember to try undoing it and see if it helps :-)

Binaries for different compilers inside same gnu session or alternatives

I am having a design problem when using GNU Make.
My problem is the following:
I have 2 executables to compile.
These binaries need to be compiled for each compiler I list in a variable, let us call it COMPILERS.
After compiling the binaries, I need to run all binaries (all of them) several times and generate, for each of them, the times in a text file.
I must put all these files together, and generate a plot out of all that data.
So, for example, if I have 3 compilers to test, I would have 6 binaries, 6 * n_of_time_to_run_benchmark and a final output with all that data, in a single plot file.
The problem with this is that my usual way to approach binary compilation is to use CXX variable, CXXFLAGS, etc. But the CXX variable is supposed to change inside the same session, which looks inconsistent to me. An example of invocation would be:
make plot COMPILERS=clang++ g++
What I did is to just compile binaries separately every time I invoke make and per compiler, making use of CXX variable.
From a script I create a folder build-clang++ and compile, I create another folder build-g++ and compile, run all benchmarks, per folder for every couple of executables for same compiler. But for this I need an external script, and this is what I want to avoid, to be able to port to windows later more easily without duplicating scripts or installing more dependencies.
What is the best way to handle this:
Use another Makefile that calls this makefile with different configurations and use it as my "script" for generating the plot? This way the makefile looks like much more traditional to me, with his separate flags, etc.
Just create all targets directly inside same Make session?
To me it looks cleaner the script solution because a Makefile is usually written in a way that the compiler is a fixed variable that does not change in the whole session.
Thank you.

how do makefile dependencies work?

I am currently confused as to how makefile targets work. I have a current understanding, and I don't know if it is correct because the tutorials I've been reading aren't very clear to me. Here is my current understanding
when you run 'make' in the terminal, the makefile utility finds the first target in the makefile and tries to run it, but before doing so it looks at all of the dependencies in the file
(this is where I start getting confused): If the dependency is a target in the makefile, but does not exist as a file in the makefile's directory, make simply runs the target. If the dependency is a file name, but not a target in the makefile, the utility checks for the existance of the file, and if the file doesn't exist, the utility yells at you. If the dependency is a file that exists in the directory AND a target, the target is run provided that any of the files that the file-target depend on are newer than the associated file.
Do I have it down right? Is it simpler than I'm making it out to be?
You have it right, more or less, but it can be stated a little more clearly. You're right about how make chooses the initial target, except of course if the user specifies a specific target on the make command line then that one is used instead of the first one.
Then make basically implements a recursive algorithm for each target, that works like this:
Find a rule to build that target. If there is no rule to build the target, make fails.
For each prerequisite of the target, run this algorithm with that prerequisite as the target.
If either the target does not exist, or if any prerequisite's modification time is newer than the target's modification time, run the recipe associated with the target. If the recipe fails, (usually) make fails.
That's it! Of course, this hides a number of complex issues: in particular item #1 (finding a rule) can be complex in situations where you have no implicit rule for the target. Also behaviors such as what to do when a rule fails can be modified.
But that's the basic algorithm!
for the question you asked your understanding is correct !!
If you are still confused have a look at this :: http://www.jfranken.de/homepages/johannes/vortraege/make_inhalt.en.html
once comfortable move to other more complete manuals like the GNU manual for make.

makefile not detecting new save file

Strange thing happening:
The idea of the makefile is to be able to compile several files at the same time. If you edit one of those files, when you type make, the only file that should compile is the one that was edited.
Now, for some reason, my makefile has decided to stop recognizing when the file has changed. So I have to: make clean and the make again to be able to compile, which is ridiculous since each time I have to compile takes about 1 minute.
Any ideas why this is happening?
I didn't add anything to my makefile; it just started doing that out of nowhere.
Something changed; programs don't stop working unless something changed. The difficulty is going to be working out what changed. You can always just type:
rm file-that-changed.o
make
to rebuild just the one file that changed, but that's a nuisance.
Is there a multi-step compilation and you have an intermediate file lying around that is confusing make?
I just had a mix up in a multi-step compilation.
If you have a non-standard file suffix that you compile into C code, and then from C into object code (or any other similar multi-step compilation), then the key to getting reliable recompilation with make is to organize the suffix list so that your extensions come at the start. Unfortunately, there isn't a standard easy way to know what the built-in suffix list is, so you end up having to do something like this:
SUFFIXES = .y .l .c .o # Yacc, Lex, C, Object files
EXTRA_SUFFIX = .xc # Extreme C, or Extended C, or ...
.SUFFIXES: # Eliminate all built-in suffixes
.SUFFIXES: ${EXTRA_SUFFIX} ${SUFFIXES}
The second .SUFFIXES line puts your extension at the front of the list. Now you can write your rules to compile your .xc file into a .c or .o file, and then when you modify the .xc file, even if there's an intermediate .c file left around, the fact that the .xc is newer than the .c or .o file will ensure that the recompilation is done.
Once upon a long time ago, the Sun version of make provided a macro called SUFFIXES which contained the default suffixes in the correct order. Sadly, that was not adopted and standardized, so you have to build the suffix list yourself. But the choice of macro name wasn't entirely accidental.

Resources