what is the difference between 'make after make clean' and just 'make'? - makefile

there are C files in a directory and I have a makefile.
I usually use makefile to compile.
I have been wandering the role of the 'make clean'
'make clean' is just to remove files.
Though I didn't use 'make clean', t
he error and warning was shown up when there were something wrong.
I cannot realize why I need to use 'make clean' whenever I change the source file.

make is a utility is to determine automatically which pieces of a large program need to be recompiled, and issue the commands to recompile them.
To prepare to use make, you must write a file called the makefile that describes the relationships among files in your program, and the states the commands for updating each file.
Once a suitable makefile exists, each time you change some source files, this simple shell command:
make
suffices to perform all necessary recompilations. The make program uses the makefile data base and the last-modification times of the files to decide which of the files need to be updated.
We generally use make clean as a generic way to tell clean up the code.ie; remove all the compiled object files from the source code. You can name it as anything you like.

It's convention only. The convention is that clean will return you to a state where all you have is the "source" files. In other words, it gets rid of everything that can be built from something else (objects, executables, listings and so on).
So make clean ; make is expected to build everything from scratch. And, in fact, you'll often find a rule like:
rebuild: clean all
which will do both steps for you.
You should never have to do a clean unless you're wanting to (for example) copy just the source files somewhere. If you have to do so after editing a file, then your Makefile is not set up correctly.
And, if you make and get an error, you should get exactly the same error if you subsequently make without fixing said error.

Related

FreeBSD make creates obj directory

Under FreeBSD, for some odd reason every time I execute a simple Makefile, it tries to create an obj directory under the current PWD.
I thought it might have to do with the default .OBJDIR for FreeBSD make, but setting .OBJDIR: ./ does not change this behavior.
This causes me problems down the line because it conflicts with SConstruct, but I managed to work around that by removing all read/write permissions for ./obj, however I still want to know why every time I run make, it tries to create the ./obj directory if it doesn't exist.
make does not create any ${.OBJDIR} automatically -- something in your Makefiles must be explicitly creating that (or trying to).
Could you post the makefile and/or the output of a make-run?
You can affect the value of the variable by setting MAKEOBJDIRPREFIX or MAKEOBJDIR in the environment or on command-line (neither can be set in /etc/make.conf).
See make(1) for more details.

Touching targets does nothing in Makefile

I keep staring at my code and wondering why touching my file does nothing:
FILES = file1 file2
myapp: $(FILES) docs/img/barline.svg
cd docs; make html
docs/img/barline.svg: docs/notebooks/barlines.ipynb docs/data/smbinning
cd docs/notebooks; jupyter nbconvert --execute --output-dir html barlines.ipynb
If I touch docs/img/barline.svg and run make, the jupyter command is not run (as it should be, shouldn't it?). The svg file is generated by running the jupyter command. If I delete it, everything works as expected, but touching seems to do nothing.
Bah, I just spend all this time writing some other answer and it turns out I misinterpreted your problem, oops.
You say that you expect jupyter to run if you touch barline.svg.
Make uses the file timestamps to determine when to run. The rule, for non-phony targets, is simple: If any of the prerequisites is newer than the target, or the target doesn't exist, then the target is rebuilt. Otherwise, it is not. In your case:
docs/img/barline.svg: docs/notebooks/barlines.ipynb docs/data/smbinning
Touching the svg won't meet the conditions for that rule, since it is the target.
Make will only run if barlines.ipynb or smbinning is newer than barline.svg. So your expectations are off, touching barline.svg won't do anything except potentially cause any targets that use it as a prerequisite to be rebuilt themselves.
For this you'd have to touch barlines.ipynb or smbinning. That'll make them newer than barlines.svg and force it to rebuild. Or you could just delete barlines.svg, as you've discovered.
Make doesn't track build timestamps in any special place elsewhere, all its info comes from the filesystem, so if you touch a target it doesn't really have anything to compare it to to say "hey somebody modified the target, maybe I should rebuild it" (and you wouldn't want that behavior anyways, for other reasons).

How to have make build from one directory if the source file exists, otherwise build from another?

I'm working on modifying a huge recursive makefile project that has 6000+ source files. All of which are clearcase controlled. Since I don't want to copy the whole source tree, I'm trying to create a new project only containing the modified source files and thus pull the source from the original tree if they don't exist in my modified tree.
I have already modified the makefile in ModDir to check if each folder exists locally and execute make in that folder if it does. Otherwise it executes make in the sourceDir. My issue lies in the subdir makefiles.
Each subdir makefile contains a list of all of the source files needed for that module. I need to find a way to build the file locally if it exists, else build the file from SourceDir/subdir.
I.e. in my image, the Dir1 makefile needs to build F1 from ModDir/Dir1/F1, and build the other files from SourceDir/Dir1/F2-F3.
I tried to use VPATH to tell make to locate the source files in both locations (ModDir first of course) which works beautifully. However, since make assumes the object files are in the ModDir, it can't find any of the object files built in SourceDir.
I also tried making a pre-build rule to modify the make file list with bash, but I don't know if that's even possible.
How do I use make to build from one directory if the source file exists (ModDir), otherwise build from another (SourceDir)?
The easiest way will be to put your "if ... then ... else" logic in an external bash or batch (whichever OS you use) script and swap makefiles before calling make

How do I get GNU make to remove intermediate directories created by implicit rules?

GNU make automatically removes intermediate files created by implicit rules, by calling rm filename at the end. This obviously doesn't work if one of the targets was actually a directory. Take the following example:
.PHONY: all
all: test.target
%.target: tempdir.%
touch $#
tempdir.%:
mkdir -p $#
make -n reveals the action plan:
mkdir -p tempdir.test
touch test.target
rm tempdir.test
Is it possible to get GNU make to correctly dispose of intermediate directories? Perhaps by changing rm to rm -rf?
There is no way to make this happen. Although GNU make prints the command "rm", really internally it's running the unlink(2) system call directly and not invoking a shell command. There is no way to configure or modify the command that GNU make runs (except by changing the source code of course).
However, I feel I should point out that it's just not going to work to use a directory as a normal prerequisite of a target. GNU make uses time-last-modified comparison to tell when targets are up to date or not, and the time-last-modified of a directory does not follow the standard rules. The TLM of a directory is updated every time a file (or subdirectory) in that directory is created, deleted, or renamed. This means you will created the directory, then have a bunch of files that depend on it: the first one is built and has timestamp N. The last one is built and has timestamp N+x. That also sets the directory's timestamp to N+x. Then the next time you run make, it will notice that the first one has an older timestamp (N) than one of its prerequisites (the directory, at N+x), and rebuild.
And this will happen forever, until it can build the remaining "out of date" prerequisites fast enough that their timestamp is not newer than the directory.
And, if you were to drop a temporary file or editor backup file or something in that directory, it would start all over again.
Just don't do it.
Some people use an explicit shell command to create directories. Some people create them as a side-effect of the target creation. Some people use order-only prerequisites to ensure they're created on time.

make doesn't see changes?

Scenario 1:
I checked out a project, and made some changes to a source file, and did make, and make sees the changes.
Scenario 2:
I checked out the project again to different directory (some reasons), copied the modified source file here, and did make and nothing happens, if I run the program, I don't see my changes, make doesn't see that I made change to this source file
make uses the timestamps of the files to determine what to build.
Perhaps your version-control system is checking all files out with the current time. When you copy your source over, it has a time in the past, making make think that the object file (presumably in your checkout) is newer than your source.
If that's the case, you can use touch to set the timestamp of a file to now.
Adding to existing answers:
To touch the targets, you can use the -t or --touch option of make. This option will not make the target but just touch it so that the next time you invoke make, the target will be made.
Alternatively you can use the -B or --always-make option which will unconditionally make the target irrespective of the modification of it's dependent(s).
okay, I just touched the copied (modified) source and now make recognizes the changes.
If you used cp to copy files options -a --archive -p --preserve will preserve the timestamp. That is not what you want!
Add option --no-preserve=timestamps
cp [options] --no-preserve=timestamps .....
Make sure you have your .PHONY tags and they are correct

Resources