I have an interesting problem. I have a makefile that builds files, then post processes them, then copies the final processed file to a release folder.
When I run make, it will build everything correctly and then finishes without copying the final target file to the release folder. I have to run make again for it to see that the generated (newly built) file is newer than the release target and will copy it over.
I have even put in a sleep 5 to delay the final release target check to allow any file IO to finish and update the newly built file with the proper timestamp.
release : ./release/file.xml
./release/file.xml : gen/file_processed.xml sleep
cp gen/file_processed.xml ./release/file.xml
gen/file_processed.xml : gen/file.xml
python2.6 post_processing_scripts.py #saves output as gen/file_processed.xml
gen/file.xml : source_files
command to compile gen/file.xml
sleep :
sleep 5
What isn't working is make thinks that after it compiles all the other targets and executes the sleep recipe to wait 5 seconds, it still says that gen/file_processed.xml is older than the release target. I have to rerun make to get that final step completed.
Any ideas as to what I can add to let the generated file finish updating before it checks it against the release target?
Thanks so much for your help, I appreciate it!
Cheers,
Brad
UPDATE:
I changed the code so that the question about the sleep command executing always is removed. it still behaves the same as described above however.
release : ./release/file.xml
./release/file.xml : gen/file_processed.xml
cp gen/file_processed.xml ./release/file.xml
gen/file_processed.xml : gen/file.xml
python2.6 post_processing_scripts.py #saves output as gen/file_processed.xml; sleep 5;
gen/file.xml : source_files
command to compile gen/file.xml
I still need to run make twice to get it to copy the final file over.
I will try and make sure this example exactly maps what my original makefile is doing.
Related
Why make rebuilds the target (I suppose) if the dependency is a binary file?
To reproduce:
create (and enter it) a new empty directory
download the GameLift SDK (it is just an example: the Makefile content on this question is an example with this file)
create a simple Makefile with the content below
issue more times the make command
all: GameLift_12_22_2020/GameLift-SDK-Release-4.0.2/GameLift-Cpp-ServerSDK-3.4.1/CMakeLists.txt
GameLift_12_22_2020/GameLift-SDK-Release-4.0.2/GameLift-Cpp-ServerSDK-3.4.1/CMakeLists.txt: GameLift_12_22_2020.zip
unzip -oq GameLift_12_22_2020.zip
I would have expected to see the unzip command to be executed only first time I issue the make command, but it continue to be executed in next make runs... why?
There are two possibilities, we cannot know which is the case with the information you've provided.
The first is that the file GameLift_12_22_2020/GameLift-SDK-Release-4.0.2/GameLift-Cpp-ServerSDK-3.4.1/CMakeLists.txt is not present in the zip file, so the second time make runs it looks to see if that file exists and it doesn't, so it re-runs the rule. If, in the same directory you run make, you use ls GameLift_12_22_2020/GameLift-SDK-Release-4.0.2/GameLift-Cpp-ServerSDK-3.4.1/CMakeLists.txt (after the unzip runs) and you get "file not found" or similar, this is your problem.
If that's not it, then the problem is that the timestamp of the file in the zip file is older than the zip file itself, and when unzip unpacks the file it sets the timestamp to this older time.
So when make goes to build it finds the CMakeLists.txt file but the modification time is older than the zip file, so make unpacks the zip file again to try to update it.
You can use ls -l to see the modification time on that file. If this is the case you should touch the file when you unpack it, so it's newer:
GameLift_12_22_2020/GameLift-SDK-Release-4.0.2/GameLift-Cpp-ServerSDK-3.4.1/CMakeLists.txt: GameLift_12_22_2020.zip
unzip -oq GameLift_12_22_2020.zip
touch $#
Is there a way to have a 'watch' target in my Makefile which would keep looping and rebuilding the project every time the source file gets changed?
I have this for my Latex project:
.PHONY : monitor
monitor:
while true; do \
inotifywait -e modify -q *.tex *.cls; make all; \
done
Interesting arguments:
-q for quiet
-r for recursive (if you want to watch the whole src folder)
-e to list specific events (if your editor does more file operations and retriggers the build way too often)
--exclude to exclude some (if your src folder contains build artifacts) to make sure the build itself will not retrigger this loop (which would be equivalent of an infinite loop without any delays)
More arguments here (inotify tools are amazing):
https://linux.die.net/man/1/inotifywait
Depending on your distribution you might have to install separate package, on my Debian I had to do
sudo apt-get install inotify-tools
I have a device installed remotely that has Internet access. As i cannot SSH directly to it, the device downloads updates from a .txt file located in a server. This .txt file is interpreted by the device as a sequence of bash instructions.
Now, i'm planning an update that requires re-compiling a C program in the device after downloading and overwritting some files. The content of the .txt file for this update looks like:
#!/bin/bash
curl -o /path-to-file/newfile.c http://myserver/newfile.c
sleep 10 #wait so it can download
cd /path-to-file
make
sleep 10 #wait to make
sudo /path-to-file/my-program #test if it worked
I previously tested this method and it worked as expected, but never tested make. A couple of questions:
Should it work?
Is the sleep after make necessary?
Here is an example of how to retrieve a source code file into another directory, change to that directory, compile the source code with make and then execute the resulting binary:
mkdir -p path-to-file/
curl -o path-to-file/newfile.c http://www.csit.parkland.edu/~cgraff1/src/hello_world.c
cd path-to-file/
make newfile
./newfile
The cd is really not an integral part of the process, but it seems as if the question specifically pertains to performing the work in a directory other than the present working directory.
I'm trying to have CMake either run three bash commands or a bash script. However, I can't seem to get it to work.
The bash commands are:
cd ${CMAKE_SOURCE_DIR}/dependencies/library
make
cd ${CMAKE_BINARY_DIR}
Essentially, I would like CMake to build the library in that directory if it does not already exist.
Here's the CMake code I tried:
if(NOT "${CMAKE_SOURCE_DIR}/dependencies/library/lib.o")
execute_process(COMMAND cd ${CMAKE_SOURCE_DIR}/dependencies/library)
execute_process(COMMAND make)
execute_process(COMMAND cd ${CMAKE_BINARY_DIR})
endif(NOT "${CMAKE_SOURCE_DIR}/dependencies/library/lib.o")
However, it's not building anything. What am I doing wrong?
Also, while I'm here asking this: should the third command, to move to the binary folder, be included?
Thanks!
execute_process() is executed during configure time. But you want this to run at build time, thus add_custom_command() and add_custom_target() is what you're looking for.
In this special case you want to generate an output file, so you should go for add_custom_command() (both are essentially the same, but command produces one or multiple output files, while target does not.
The cmake snippet for this should look something like the following:
add_custom_command(
OUTPUT ${CMAKE_SOURCE_DIR}/dependencies/library/lib.o
WORKING_DIRECTORY ${CMAKE_SOURCE_DIR}/dependencies/library
COMMAND make
)
You then have to add the output file in another target as dependency, and everything should (hopefully) work as expected.
You can also add DEPENDS statements to the add_custom_command() call to rebuild the object file in case some input sources have changed.
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