我有一个“C”/C++ CMake 项目,运行良好。但是,我有时会在时间略有不同的远程集群上(重新)构建。这台机器运行 Linux,我正在使用make
. 我想知道是否有一些 make/CMake 方法可以更改检测文件更改的方式,例如更改为 MD5 或 diff 而不是使用时间戳。否则我想我要么必须忍受恒定make clean
/make -j
周期,要么必须在每次使用该特定服务器时更改我的当地时间。
我正在查看 CMake 文档,看看是否有一个标志可以更改这些设置,但没有找到。这在没有 RTC 的平台(例如 Raspberry)上如何工作?
是的,所以知道 CMake /make
没有做我想要的事情,并且我不想将我的机器的时间同步到目标的麻烦,我想出了以下方法:
#!/bin/bash
touch src_hash.md5
echo -n make "$@" > mymake.sh
find `pwd`/../src `pwd`/../include -print0 |
while IFS= read -r -d $'\0' f; do
if [[ ! -d "$f" ]]; then
MD5=`md5sum "$f" | awk -v fn="$f" '{ print "\"" fn "\" " $1; }'`
echo $MD5 >> src_hash.md5.new
OLDMD5=`grep -e "^\"$f\"" src_hash.md5`
if [[ "$OLDMD5" == "" ]]; then
echo "$MD5 -- [a new file]"
continue # a new file, make can handle that well on its own
fi
HASH=`echo $MD5 | awk '{ print $2; }'`
OLDHASH=`echo $OLDMD5 | awk '{ print $2; }'`
if [[ "$HASH" != "$OLDHASH" ]]; then
echo "$MD5 -- changed from $OLDHASH"
echo -n " \"--what-if=${f}\"" >> mymake.sh
# this is running elsewhere, can't pass stuff via variables
fi
fi
done
touch src_hash.md5.new
mv src_hash.md5.new src_hash.md5
echo using: `cat mymake.sh`
echo >> mymake.sh # add a newline
chmod +x mymake.sh
./mymake.sh
rm -f mymake.sh
Run Code Online (Sandbox Code Playgroud)
这会保留源文件哈希值列表src_hash.md5
,并且每次运行时都会将当前文件与这些哈希值进行比较(并相应地更新列表)。
最后,它调用make
,将您提供给脚本的任何参数传递给脚本(例如-j
)。它利用了--what-if=
开关,告诉它make
像给定的文件更改一样进行操作 - 这样可以优雅地处理构建目标对源/标头的依赖关系。
您可能还想将源/包含文件的路径作为参数传递,以便这些文件不会在内部进行硬编码。
或者对上述脚本进行再一次迭代,用于touch
更改和恢复文件时间戳,以应对make
非常顽固地不重建任何内容的情况:
#!/bin/bash
if [[ ! -d ../src ]]; then
>&2 echo "error: ../src is not a directory or does not exist"
exit -1
fi
if [[ ! -d ../include ]]; then
>&2 echo "error: ../include is not a directory or does not exist"
exit -1
fi
echo "Scanning for changed files in ../src and ../include"
touch src_hash.md5 # in case this runs for the first time
rm -f mymaketouch.sh
rm -f mymakerestore.sh
touch mymaketouch.sh
touch mymakerestore.sh
echo -n make "$@" > mymake.sh
CWD="`pwd`"
find ../src ../include -print0 |
while IFS= read -r -d $'\0' f; do
if [[ ! -d "$f" ]]; then
fl=`readlink -f "$CWD/$f"`
MD5=`md5sum "$fl" | awk -v fn="$fl" '{ print "\"" fn "\" " $1; }'`
HASH=`echo $MD5 | awk '{ print $2; }'`
echo $MD5 >> src_hash.md5.new
OLDMD5=`grep -e "^\"$fl\"" src_hash.md5`
OLDHASH=`echo $OLDMD5 | awk '{ print $2; }'`
if [[ "$OLDMD5" == "" ]]; then
echo "$f $HASH -- [a new file]"
continue # a new file, make can handle that well on its own
fi
if [[ "$HASH" != "$OLDHASH" ]]; then
echo "$f $HASH -- changed from $OLDHASH"
echo "touch -m \"$fl\"" >> mymaketouch.sh # will touch it and change modification time
stat "$fl" -c "touch -m -d \"%y\" \"%n\"" >> mymakerestore.sh # will restore it later on so that we do not run into problems when copying newer from a different system
echo -n " \"--what-if=$fl\"" >> mymake.sh
# this is running elsewhere, can't pass stuff via variables
fi
fi
done
echo using: `cat mymake.sh`
echo >> mymake.sh # add a newline
echo 'exit $?' >> mymake.sh
chmod +x mymaketouch.sh
chmod +x mymakerestore.sh
chmod +x mymake.sh
control_c() # run if user hits control-c
{
echo -en "\nrestoring modification times\n"
./mymakerestore.sh
rm -f mymaketouch.sh
rm -f mymakerestore.sh
rm -f mymake.sh
rm -f src_hash.md5.new
exit -1
}
trap control_c SIGINT
./mymaketouch.sh
./mymake.sh
RETVAL=$?
./mymakerestore.sh
rm -f mymaketouch.sh
rm -f mymakerestore.sh
rm -f mymake.sh
touch src_hash.md5.new # in case there was nothing new
mv src_hash.md5.new src_hash.md5
# do it now in case someone hits ctrl+c mid-build and not all files are built
exit $RETVAL
Run Code Online (Sandbox Code Playgroud)
或者,如果您正在构建一个大型项目,甚至可以并行运行哈希:
#!/bin/bash
if [[ ! -d ../src ]]; then
>&2 echo "error: ../src is not a directory or does not exist"
exit -1
fi
if [[ ! -d ../include ]]; then
>&2 echo "error: ../include is not a directory or does not exist"
exit -1
fi
echo "Scanning for changed files in ../src and ../include"
touch src_hash.md5 # in case this runs for the first time
rm -f mymaketouch.sh
rm -f mymakerestore.sh
touch mymaketouch.sh
touch mymakerestore.sh
echo -n make "$@" > mymake.sh
CWD="`pwd`"
rm -f src_hash.md5.new # will use ">>", make sure to remove the file
find ../src ../include -print0 |
while IFS= read -r -d $'\0' f; do
if [[ ! -d "$f" ]]; then
fl="$CWD/$f"
(echo `md5sum "$f" | awk -v fn="$fl" '{ print "\"" fn "\" " $1; }'` ) & # parallel, echo is atomic (http://stackoverflow.com/questions/9926616/is-echo-atomic-when-writing-single-lines)
# run in parallel (remove the ampersand if you run into trouble)
fi
done >> src_hash.md5.new # >> is atomic but > wouldn't be
# this is fast
cat src_hash.md5 > src_hash.md5.diff
echo separator >> src_hash.md5.diff
cat src_hash.md5.new >> src_hash.md5.diff
# make a compound file for awk (could also read the other file in awk but this seems simpler right now)
cat src_hash.md5.diff | awk 'BEGIN { FS="\""; had_sep = 0; }
{
if(!had_sep && $1 == "separator")
had_sep = 1;
else {
sub(/[[:space:]]/, "", $3);
if(!had_sep)
old_hashes[$2] = $3;
else {
f = $2;
if((idx = index(f, "../")) != 0)
f = substr(f, idx, length(f) - idx + 1);
if($2 in old_hashes) {
if(old_hashes[$2] != $3)
print "\"" f "\" " $3 " -- changed from " old_hashes[$2];
} else
print "\"" f "\" -- a new file " $3;
}
}
}'
# print verbose for the user only
cat src_hash.md5.diff | awk 'BEGIN { FS="\""; had_sep = 0; }
{
if(!had_sep && $1 == "separator")
had_sep = 1;
else {
sub(/[[:space:]]/, "", $3);
if(!had_sep)
old_hashes[$2] = $3;
else {
if($2 in old_hashes) {
if(old_hashes[$2] != $3)
printf($2 "\0"); /* use \0 as a line separator for the below loop */
}
}
}
}' |
while IFS= read -r -d $'\0' fl; do
echo "touch -m \"$fl\"" >> mymaketouch.sh # will touch it and change modification time
stat "$fl" -c "touch -m -d \"%y\" \"%n\"" >> mymakerestore.sh # will restore it later on so that we do not run into problems when copying newer from a different system
echo -n " \"--what-if=$fl\"" >> mymake.sh
# this is running elsewhere, can't pass stuff via variables
done
# run again, handle files that require change
rm -f src_hash.md5.diff
echo using: `cat mymake.sh`
echo >> mymake.sh # add a newline
echo 'exit $?' >> mymake.sh
chmod +x mymaketouch.sh
chmod +x mymakerestore.sh
chmod +x mymake.sh
control_c() # run if user hits control-c
{
echo -en "\nrestoring modification times\n"
./mymakerestore.sh
rm -f mymaketouch.sh
rm -f mymakerestore.sh
rm -f mymake.sh
rm -f src_hash.md5.new
exit -1
}
trap control_c SIGINT
./mymaketouch.sh
./mymake.sh
RETVAL=$?
./mymakerestore.sh
rm -f mymaketouch.sh
rm -f mymakerestore.sh
rm -f mymake.sh
touch src_hash.md5.new # in case there was nothing new
mv src_hash.md5.new src_hash.md5
# do it now in case someone hits ctrl+c mid-build and not all files are built
exit $RETVAL
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
6078 次 |
最近记录: |