BASH脚本 自动编译
目标
为这个椭圆检测(Github)程序实现自动编译。
思路流程
• 1. 自动下载代码
• 2. 为代码生成 makefile
• 3. 检测 opencv 是否安装和版本,如果版本过低则通过脚本自动安装
比较的方法。
• 4. 编译生成可执行文件并执行
生成makefile
这里makefile 是按照GenericMakefile Github模板修改的,直接写在sh脚本里边。这里有几个注意事项,首先是makefile 文件中有许多的特殊字符与sh脚本中的重复,这里我们要用转义符进行保护。
\->\\ `->\` $->\$
写入多行文本
cat>Makefile<<EOF
#### PROJECT SETTINGS ####
# Function used to check variables. Use on the command line:
print-%: ; @echo \$*=\$(\$*)
#多行文本
EOF
版本号获取与比较
思路是先获取版本号,然后和要求的版本号用 sort函数进行排序,并判断第一个与要求的是否一致。调用
# 比较版本号大小
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
#调用方法
require_opencv_version="2.4.9"
opencv_version=`pkg-config --modversion opencv` #获取版本号
if version_ge $opencv_version $require_opencv_version; then
echo "current opencv version: $opencv_version is satisified"
else
echo "current opencv is not satisified"
cd setup
bash install-opencv-2.4.13.sh
cd ..
fi
#!/bin/bash
VERSION=$1
VERSION2=$2
function version_gt() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" != "$1"; } #大于
function version_le() { test "$(echo "$@" | tr " " "\n" | sort -V | head -n 1)" == "$1"; } #小于等于
function version_lt() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" != "$1"; } #小于
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; } #大于等于
if version_gt $VERSION $VERSION2; then
echo "$VERSION is greater than $VERSION2"
fi
if version_le $VERSION $VERSION2; then
echo "$VERSION is less than or equal to $VERSION2"
fi
if version_lt $VERSION $VERSION2; then
echo "$VERSION is less than $VERSION2"
fi
if version_ge $VERSION $VERSION2; then
echo "$VERSION is greater than or equal to $VERSION2"
fi
流程图
代码
#!/bin/bash
require_opencv_version="2.4.9"
# 比较版本号大小
function version_ge() { test "$(echo "$@" | tr " " "\n" | sort -rV | head -n 1)" == "$1"; }
function showpatherror()
{
echo "The dir doesn't exsit! Please check!"
echo "Uisng 'install_auto.sh -h' to show help"
# echo "Create by Li Haojia(Derek Lee) 2019.11.25"
exit
}
function showhelp()
{
echo "Uisng 'install_auto.sh' to build and install the program in current dir."
echo "Uisng 'install_auto.sh [dir]' to build and install the program in the path you want."
echo "Uisng 'install_auto.sh -h' to show help"
# echo "Create by Li Haojia(Derek Lee) 2019.11.25"
exit
}
# 生成makefile
function write_makefile()
{
ADDLIBS=$@ #添加依赖库
FILE_BIN_NAME=EllipseDetector #产生的应用程序名
echo "Create Makefile"
cat>Makefile<<EOF
#### PROJECT SETTINGS ####
# The name of the executable to be created
BIN_NAME := ${FILE_BIN_NAME}
# Compiler used
CXX ?= g++
# Extension of source files used in the project
SRC_EXT = cpp
# Path to the source directory, relative to the makefile
SRC_PATH = .
# Space-separated pkg-config libraries used by this project
LIBS = ${ADDLIBS}
# General compiler flags
COMPILE_FLAGS = -std=c++11 -Wall -Wextra -g
# Additional release-specific flags
RCOMPILE_FLAGS = -D NDEBUG
# Additional debug-specific flags
DCOMPILE_FLAGS = -D DEBUG
# Add additional include paths
INCLUDES = -I \$(SRC_PATH)
# General linker settings
LINK_FLAGS =
# Additional release-specific linker settings
RLINK_FLAGS =
# Additional debug-specific linker settings
DLINK_FLAGS =
# Destination directory, like a jail or mounted system
DESTDIR = /
# Install path (bin/ is appended automatically)
INSTALL_PREFIX = usr/local
#### END PROJECT SETTINGS ####
# Optionally you may move the section above to a separate config.mk file, and
# uncomment the line below
# include config.mk
# Generally should not need to edit below this line
# Obtains the OS type, either 'Darwin' (OS X) or 'Linux'
UNAME_S:=\$(shell uname -s)
# Function used to check variables. Use on the command line:
# make print-VARNAME
# Useful for debugging and adding features
print-%: ; @echo \$*=\$(\$*)
# Shell used in this makefile
# bash is used for 'echo -en'
SHELL = /bin/bash
# Clear built-in rules
.SUFFIXES:
# Programs for installation
INSTALL = install
INSTALL_PROGRAM = \$(INSTALL)
INSTALL_DATA = \$(INSTALL) -m 644
# Append pkg-config specific libraries if need be
ifneq (\$(LIBS),)
COMPILE_FLAGS += \$(shell pkg-config --cflags \$(LIBS))
LINK_FLAGS += \$(shell pkg-config --libs \$(LIBS))
endif
# Verbose option, to output compile and link commands
export V := false
export CMD_PREFIX := @
ifeq (\$(V),true)
CMD_PREFIX :=
endif
# Combine compiler and linker flags
release: export CXXFLAGS := \$(CXXFLAGS) \$(COMPILE_FLAGS) \$(RCOMPILE_FLAGS)
release: export LDFLAGS := \$(LDFLAGS) \$(LINK_FLAGS) \$(RLINK_FLAGS)
debug: export CXXFLAGS := \$(CXXFLAGS) \$(COMPILE_FLAGS) \$(DCOMPILE_FLAGS)
debug: export LDFLAGS := \$(LDFLAGS) \$(LINK_FLAGS) \$(DLINK_FLAGS)
# Build and output paths
release: export BUILD_PATH := build/release
release: export BIN_PATH := bin/release
debug: export BUILD_PATH := build/debug
debug: export BIN_PATH := bin/debug
install: export BIN_PATH := bin/release
# Find all source files in the source directory, sorted by most
# recently modified
ifeq (\$(UNAME_S),Darwin)
SOURCES = \$(shell find \$(SRC_PATH) -name '*.\$(SRC_EXT)' | sort -k 1nr | cut -f2-)
else
SOURCES = \$(shell find \$(SRC_PATH) -name '*.\$(SRC_EXT)' -printf '%T@\t%p\n' \\
| sort -k 1nr | cut -f2-)
endif
# fallback in case the above fails
rwildcard = \$(foreach d, \$(wildcard \$1*), \$(call rwildcard,\$d/,\$2) \\
\$(filter \$(subst *,%,\$2), \$d))
ifeq (\$(SOURCES),)
SOURCES := \$(call rwildcard, \$(SRC_PATH), *.\$(SRC_EXT))
endif
# Set the object file names, with the source directory stripped
# from the path, and the build path prepended in its place
OBJECTS = \$(SOURCES:\$(SRC_PATH)/%.\$(SRC_EXT)=\$(BUILD_PATH)/%.o)
# Set the dependency files that will be used to add header dependencies
DEPS = \$(OBJECTS:.o=.d)
# Macros for timing compilation
ifeq (\$(UNAME_S),Darwin)
CUR_TIME = awk 'BEGIN{srand(); print srand()}'
TIME_FILE = \$(dir \$@).\$(notdir \$@)_time
START_TIME = \$(CUR_TIME) > \$(TIME_FILE)
END_TIME = read st < \$(TIME_FILE) ; \\
\$(RM) \$(TIME_FILE) ; \\
st=\$\$((\`\$(CUR_TIME)\` - \$\$st)) ; \\
echo \$\$st
else
TIME_FILE = \$(dir \$@).\$(notdir \$@)_time
START_TIME = date '+%s' > \$(TIME_FILE)
END_TIME = read st < \$(TIME_FILE) ; \\
\$(RM) \$(TIME_FILE) ; \\
st=\$\$((\`date '+%s'\` - \$\$st - 86400)) ; \\
echo \`date -u -d @\$\$st '+%H:%M:%S'\`
endif
# Standard, non-optimized release build
.PHONY: release
release: dirs
ifeq (\$(USE_VERSION), true)
@echo "Beginning release build v\$(VERSION_STRING)"
else
@echo "Beginning release build"
endif
@\$(START_TIME)
@\$(MAKE) all --no-print-directory
@echo -n "Total build time: "
@\$(END_TIME)
# Debug build for gdb debugging
.PHONY: debug
debug: dirs
ifeq (\$(USE_VERSION), true)
@echo "Beginning debug build v\$(VERSION_STRING)"
else
@echo "Beginning debug build"
endif
@\$(START_TIME)
@\$(MAKE) all --no-print-directory
@echo -n "Total build time: "
@\$(END_TIME)
# Create the directories used in the build
.PHONY: dirs
dirs:
@echo "Creating directories"
@mkdir -p \$(dir \$(OBJECTS))
@mkdir -p \$(BIN_PATH)
# Installs to the set path
.PHONY: install
install:
@echo "Installing to \$(DESTDIR)\$(INSTALL_PREFIX)/bin"
@\$(INSTALL_PROGRAM) \$(BIN_PATH)/\$(BIN_NAME) \$(DESTDIR)\$(INSTALL_PREFIX)/bin
# Uninstalls the program
.PHONY: uninstall
uninstall:
@echo "Removing \$(DESTDIR)\$(INSTALL_PREFIX)/bin/\$(BIN_NAME)"
@\$(RM) \$(DESTDIR)\$(INSTALL_PREFIX)/bin/\$(BIN_NAME)
# Removes all build files
.PHONY: clean
clean:
@echo "Deleting \$(BIN_NAME) symlink"
@\$(RM) \$(BIN_NAME)
@echo "Deleting directories"
@\$(RM) -r build
@\$(RM) -r bin
# Main rule, checks the executable and symlinks to the output
all: \$(BIN_PATH)/\$(BIN_NAME)
@echo "Making symlink: \$(BIN_NAME) -> \$<"
@\$(RM) \$(BIN_NAME)
@ln -s \$(BIN_PATH)/\$(BIN_NAME) \$(BIN_NAME)
# Link the executable
\$(BIN_PATH)/\$(BIN_NAME): \$(OBJECTS)
@echo "Linking: \$@"
@\$(START_TIME)
\$(CMD_PREFIX)\$(CXX) \$(OBJECTS) \$(LDFLAGS) -o \$@
@echo -en "\t Link time: "
@\$(END_TIME)
# Add dependency files, if they exist
-include \$(DEPS)
# Source file rules
# After the first compilation they will be joined with the rules from the
# dependency files to provide header dependencies
\$(BUILD_PATH)/%.o: \$(SRC_PATH)/%.\$(SRC_EXT)
@echo "Compiling: \$< -> \$@"
@\$(START_TIME)
\$(CMD_PREFIX)\$(CXX) \$(CXXFLAGS) \$(INCLUDES) -MP -MMD -c \$< -o \$@
@echo -en "\t Compile time: "
@\$(END_TIME)
EOF
}
###########################################################################
## main
echo "Create by Li Haojia(Derek Lee) 2019.11.25"
if [[ -n $1 ]]; then
if [[ $1 == "-h" ]]||[[ $1 == "--help" ]]; then
showhelp
elif [ ! -d $1 ]; then
showpatherror
else
folder=$1
echo "We will download and build at ${folder}"
cd ${folder}
fi
else
echo "We will download and build at ${PWD}"
fi
if [ -d "fast_ellipse_detector" ]
then
echo -e "fast_ellipse_detector floder exists."
read -r -p "Do you want to delet it and download again?[Y/n]" input
case $input in
[yY][eE][sS]|[yY])
echo "Delet"
rm -r -f fast_ellipse_detector
echo "Get source files"
git clone https://github.com/h3ct0r/fast_ellipse_detector.git
;;
esac
else
echo "Get source files"
git clone https://github.com/h3ct0r/fast_ellipse_detector.git
fi
echo "Dowload finished"
cd fast_ellipse_detector
opencv_version=`pkg-config --modversion opencv`
if version_ge $opencv_version $require_opencv_version; then
echo "current opencv version: $opencv_version is satisified"
else
echo "current opencv is not satisified"
cd setup
bash install-opencv-2.4.13.sh
cd ..
fi
write_makefile opencv
make
echo "Finished!"