2017-04-21 63 views
-2

我終於厭倦了makefile,並編寫了自己的bash腳本來編譯。我寫了所有的東西,它的效果很好,但由於某種原因,當我嘗試用ctrl-c取消它時,它有時會凍結。這裏是腳本:Bash腳本在發送時凍結SIGINT

#!/bin/bash 

# Just to see if the script even sees the SIGINT 
trap caught SIGINT 
caught() { echo "hi"; } 

compile() { 
    cpp=$(echo "$1" | sed -e 's/$/.cpp/' -e 's/^/src\//') 
    o=$(echo "$1" | sed -e 's/$/.o/' -e "s/^/$build_dir\//") 
    echo "$compile -c $cpp -o $o" 
    eval "$compile -c $cpp -o $o" 
    return $? 
} 

# I know this isn't normal, but I hate it when I forget to include something 
# in the header and it fails way down the line 
compile_h() { 
    h=$(echo "$1" | sed -e 's/$/.h/' -e 's/^/src\//') 
    o=$(echo "$1" | sed -e 's/$/.o/' -e "s/^/$build_dir\/headers\//") 
    echo "$compile -c $h -o /dev/null" 
    eval "$compile -x c++ -c $h -o $o" 
    if [ $? -ne 0 ]; then 
     return 1 
    fi 
    rm "$o" 
    return 0 
} 

build_type=$(awk 'NR==1' .build_options) 
compile_command_debug=$(awk 'NR==2' .build_options) 
link_command_debug=$(awk 'NR==3' .build_options) 
compile_command_production=$(awk 'NR==4' .build_options) 
link_command_production=$(awk 'NR==5' .build_options) 
libraries=$(awk 'NR==6' .build_options) 

# Make options for this build 
build_dir="build" 
compile="$compile_command_debug" 
link="$link_command_debug" 
if [ "$build_type" == "production" ]; then 
    build_dir="buildp" 
    compile="$compile_command_production" 
    link="$link_command_production" 
fi 
# These options need to be changeable later 
output="game" 
job_number=5 

# There are more options, but they aren't important for this problem 
while [ "$1" != "" ]; do 
    if [ "$1" == "clean" ]; then 
     rm -r $build_dir/* 
    fi 
    shift 
done 

# Get filenames 
cpps=$(find src -name *.cpp | sed -e 's/src\///' -e 's/.cpp//' | sort) 
hs=$(find src -name *.h | sed -e 's/src\///' -e 's/.h//' | sort) 

# Ensure that all directories exist 
directories=$(find src -type d | tail --lines=+2 | sed 's/src\///' | sort) 
if [ ! -d "$build_dir/headers" ]; then 
    mkdir "$build_dir/headers" 
fi 
for dir in $directories; do 
    if [ ! -d "$build_dir/$dir" ]; then 
     mkdir "$build_dir/$dir" 
    fi 
    if [ ! -d "$build_dir/headers/$dir" ]; then 
     mkdir "$build_dir/headers/$dir" 
    fi 
done 

all_o="" # To be used for linking 
# Determine what files need to be compiled 
cpp_needed="" 
h_needed="" 
link_needed=false 
# Check cpp files 
for cpp_base in $cpps; do 
    o=$(echo "$cpp_base" | sed -e 's/$/.o/' -e "s/^/$build_dir\//") 
    all_o="$all_o $o" 
    d_file=$(echo "$cpp_base" | sed -e 's/$/.d/' -e "s/^/$build_dir\//") 
    if [ -f "$d_file" ]; then 
     d=$(<"$d_file") 
     d=$(echo "$d" | tr " " "\n" | tail --lines=+2 | grep "s") 
     if [ "$link_needed" = false ]; then 
      if [ "$o" -nt "$output" ]; then 
       link_needed=true 
      fi 
     fi 
     for dep in $d; do 
      if [ "$dep" -nt "$o" ]; then 
       if [ "$cpp_needed" == "" ]; then cpp_needed="$cpp_base" 
       else cpp_needed="$cpp_needed $cpp_base" 
       fi 
       link_needed=true 
       break 
      fi 
     done 
    else 
     if [ "$cpp_needed" == "" ]; then cpp_needed="$cpp_base" 
     else cpp_needed="$cpp_needed $cpp_base" 
     fi 
     link_needed=true 
    fi 
done 
# Check h files 
for h_base in $hs; do 
    d_file=$(echo "$h_base" | sed -e 's/$/.d/' -e "s/^/$build_dir\/headers\//") 
    if [ -f "$d_file" ]; then 
     d=$(<"$d_file") 
     d=$(echo "$d" | tr " " "\n" | tail --lines=+2 | grep "s") 
     for dep in $d; do 
      if [ "$dep" -nt "$d_file" ]; then 
       if [ "$h_needed" == "" ]; then h_needed="$h_base" 
       else h_needed="$h_needed $h_base" 
       fi 
       break 
      fi 
     done 
    else 
     if [ "$h_needed" == "" ]; then h_needed="$h_base" 
     else h_needed="$h_needed $h_base" 
     fi 
    fi 
done 

# Compile 
did_something=false 
# Compile hs 
while [ "$h_needed" != "" ]; do 
    for index in $(seq 1 $job_number); do 
     if [ "$h_needed" == "" ]; then break; fi 
     if ! kill -0 ${pids[index]} 2>/dev/null; then 
      new_file=$(echo "$h_needed" | awk '{print $1;}') 
      if [ $(echo "$h_needed" | wc -w) -eq 1 ]; then h_needed="" 
      else h_needed=$(echo "$h_needed" | cut -d " " -f2-) 
      fi 
      compile_h "$new_file" & 
      pids[index]=$! 
      did_something=true 
     fi 
    done 
    wait -n 
    if [ $? -ne 0 ]; then 
     wait 
     exit 1 
    fi 
done 
while [ $(pgrep -c -P$$) -gt 0 ]; do 
    wait -n 
    if [ $? -ne 0 ]; then 
     wait 
     exit 1 
    fi 
done 

# Compile cpps 
while [ "$cpp_needed" != "" ]; do 
    for index in $(seq 1 $job_number); do 
     if [ "$cpp_needed" == "" ]; then break; fi 
     if ! kill -0 ${pids[index]} 2>/dev/null; then 
      new_file=$(echo "$cpp_needed" | awk '{print $1;}') 
      if [ $(echo "$cpp_needed" | wc -w) -eq 1 ]; then cpp_needed="" 
      else cpp_needed=$(echo "$cpp_needed" | cut -d " " -f2-) 
      fi 
      compile "$new_file" & 
      pids[index]=$! 
      did_something=true 
     fi 
    done 
    wait -n 
    if [ $? -ne 0 ]; then 
     wait 
     exit 1 
    fi 
done 
while [ $(pgrep -c -P$$) -gt 0 ]; do 
    wait -n 
    if [ $? -ne 0 ]; then 
     wait 
     exit 1 
    fi 
done 

# Compile program 
if [ "$link_needed" = true ]; then 
    echo "$link $all_o -o game $libraries" 
    eval "$link $all_o -o game $libraries" 
    did_something=true 
fi 
# Make a message if nothing compiled 
if [ "$did_something" = false ]; then 
    echo "Program is already compiled." 
fi 

它通常是完美的。但是,有時候,當我嘗試用ctrl-c取消它時,它會凍結。通過一些調試,我發現當腳本沒有創建新的工作時,ctrl-c就可以正常工作。但是當它處於創建新工作的中間時,它會凍結劇本。它甚至不會捕獲SIGINT(這是「回聲嗨」的東西是在頂部)。我真的不知道發生了什麼事。有人知道發生了什麼事嗎?謝謝!

編輯:我意識到我應該提到我使用g ++來編譯。

再次編輯:這是一個更簡化的腳本版本。你仍然需要設置一些文件進行編譯,如果你想測試一下:

#!/bin/bash 

# Just to see if the script even sees the SIGINT 
trap caught SIGINT 
caught() { echo "hi"; } 

# I know this isn't normal, but I hate it when I forget to include something 
# in the header and it fails way down the line 
compile_h() { 
    h=$(echo "$1" | sed -e 's/$/.h/' -e 's/^/src\//') 
    o=$(echo "$1" | sed -e 's/$/.o/' -e "s/^/$build_dir\/headers\//") 
    echo "$compile -c $h -o /dev/null" 
    eval "$compile -x c++ -c $h -o $o" 
    if [ $? -ne 0 ]; then 
     return 1 
    fi 
    rm "$o" 
    return 0 
} 

build_type="debug" 
build_dir="build" 
compile="g++" 
job_number=5 

# Get filenames 
hs=$(find src -name *.h | sed -e 's/src\///' -e 's/.h//' | sort) 
h_needed=$(echo $hs) 

# Compile hs 
while [ "$h_needed" != "" ]; do 
    for index in $(seq 1 $job_number); do 
     if [ "$h_needed" == "" ]; then break; fi 
     if ! kill -0 ${pids[index]} 2>/dev/null; then 
      new_file=$(echo "$h_needed" | awk '{print $1;}') 
      if [ $(echo "$h_needed" | wc -w) -eq 1 ]; then h_needed="" 
      else h_needed=$(echo "$h_needed" | cut -d " " -f2-) 
      fi 
      compile_h "$new_file" & 
      pids[index]=$! 
      did_something=true 
     fi 
    done 
    wait -n 
    if [ $? -ne 0 ]; then 
     wait 
     exit 1 
    fi 
done 
while [ $(pgrep -c -P$$) -gt 0 ]; do 
    wait -n 
    if [ $? -ne 0 ]; then 
     wait 
     exit 1 
    fi 
done 
+1

試着理解[mcve]。在這種情況下,尤其是「minimal」這個詞:) – jm666

+0

......另外,最好使用configure + makefile作爲你自己發明的解決方案......(僅僅是imho)。 – jm666

+0

我已經擺脫了我的實際版本的很多東西。問題是我不確定問題出在哪裏。 – sudgy

回答

0

,你在你的腳本運行時,可能會覆蓋你的陷阱,並建立了自己的任何程序。例如,該陷阱可能由於某種原因導致當前正在運行的程序崩潰。發生這種情況時,請查看ps wafux中的進程樹以查找最可能的罪魁禍首。例如,當進程不在任何地方時,殭屍(Z)或不可中斷睡眠(D)進程狀態(請參見man ps)很常見。

+0

所有的孩子g ++都不見了,但腳本本身處於「R +」狀態,它表示它仍然在運行。 – sudgy