leveldb学习之路 --build_detect_platform 解读
韩照
2023-12-01
看了整个include/leveldb/的头文件内容之后,对于模块的划分,文件之间的关联等毫无头绪,我觉得应该是策略出错了。
硬看leveldb的代码效果真的很差,我觉得首先应该划分模块,然后按照模块阅读代码。
根据makefile中文件编译的依赖性关系,以及先后顺序,可以看出大致的模块的划分。
阅读Makefile的时候发现先调用了build_detect_platform这个shell脚本,生成一个build_config.mk的文件。
我对于shell脚本的认识非常粗浅,借此机会也多学学,能学多少是多少。
#!bin/sh
/*
创建shell脚本文件的时,必须在文件的第一行指定要使用的shell,
其格式如上:#!bin/sh
在通常的shell脚本中,井号(#)用作注释行,注释行是不被shell执行的。
然而,shell脚本文件的第一行是一个特例,井号后接感叹号告诉shell用哪个shell来运行脚本。
*/
# Detects OS we're compiling on and outputs a file
# specified by the first argument, which in turn
# gets read while processing Makefile.
/*
检测编译的平台,使用调用脚本时传入的参数,作为输出文件的文件名。
(就是指build_config.mk)
*/
# The output will set the following variables:
# CC C Compiler path
# CXX C++ Compiler path
# PLATFORM_LDFLAGS Linker flags
# PLATFORM_LIBS Libraries flags
# PLATFORM_SHARED_EXT Extension for shared libraries
# PLATFORM_SHARED_LDFLAGS Flags for building shared library
# This flag is embedded just before
# the name of the shared library
# without intervening spaces
# PLATFORM_SHARED_CFLAGS Flags for compiling objects for
# shared library
# PLATFORM_CCFLAGS C compiler flags
# PLATFORM_CXXFLAGS C++ compiler flags. Will contain:
# PLATFORM_SHARED_VERSIONED Set to 'true' if platform supports
# versioned shared libraries, empty
# otherwise.
#
# The PLATFORM_CCFLAGS and PLATFORM_CXXFLAGS might include the
# following:
#
# -DLEVELDB_ATOMIC_PRESENT if <atomic> is present
# -DLEVELDB_PLATFORM_POSIX for Posix-based platforms
# -DSNAPPY if the Snappy library is present
/*
生成的build_config.mk里,设置了以上这些参数。
*/
OUTPUT=$1
PREFIX=$2
/*
$1,$2分别表示执行
./build_detect_platform build_config.mk ./
时传入的第一个参数 build_config.mk和第二个参数./
*/
if test -z "$OUTPUT" || test -z "$PREFIX"; then
echo "usage: $0 <output-filename> <directory_prefix>" >&2
exit 1
fi
/*
test -z xxx 测试xxx的长度是否为0,0为true,非0为false。
即为测试第一个参数和第二个参数时候为空,如果为空,输出错误提示。
"$0"为shell本身的名字
">&2"为重定向内容到文件描述符"2"中("2"为标准错误)。
如果写成">2"会解释成将内容重定向到"2"这个文件,前加写成">&2"即可避免!
*/
# Delete existing output, if it exists
rm -f $OUTPUT
touch $OUTPUT
/*
删除已有的build_config.mk
创建一个空的build_config.mk
这应该是考虑了重新运行makefile是出现的问题
*/
if test -z "$CC"; then
CC=cc
fi
if test -z "$CXX"; then
CXX=g++
fi
if test -z "$TMPDIR"; then
TMPDIR=/tmp
fi
/*
分别检测"$CC","$CXX","$TMPDIR"这些变量是否为空
如果为空,就分别赋值为"cc","g++","/tmp"
*/
# Detect OS
if test -z "$TARGET_OS"; then
TARGET_OS=`uname -s`
fi
/*
uname -s命令将输出目前的平台
检测"$TARGET_OS"是否为空
如果为空,赋值为目前的平台名
*/
COMMON_FLAGS=
CROSS_COMPILE=
PLATFORM_CCFLAGS=
PLATFORM_CXXFLAGS=
PLATFORM_LDFLAGS=
PLATFORM_LIBS=
PLATFORM_SHARED_EXT="so"
PLATFORM_SHARED_LDFLAGS="-shared -Wl,-soname -Wl,"
PLATFORM_SHARED_CFLAGS="-fPIC"
PLATFORM_SHARED_VERSIONED=true
/*
PLATFORM_SHARED_EXT="so"
PLATFORM_SHARED_LDFAGS="-shared -Wl,-soname -Wl,"
PLATFORM_SHARED_CFLAGS="-fPIC"
这三个变量是创建共享库时,编译所需要的参数。
下面是使用a.c和b.c创建共享库的示例:
gcc -fPIC -g -c -Wall a.c
gcc -fPIC -g -c -Wall b.c
gcc -share -WI,-soname,libmyab.so.1 -o libmyab.so.1.0.1 a.o b.o -lc
(关于共享库可以看我转载的另外一篇博客:关于shared library的描述)
*/
MEMCMP_FLAG=
if [ "$CXX" = "g++" ]; then
# Use libc's memcmp instead of GCC's memcmp.
# This results in ~40%
# performance improvement on readrandom under
# gcc 4.4.3 on Linux/x86.
MEMCMP_FLAG="-fno-builtin-memcmp"
fi
/*
使用自己定义的库函数memcmp,在随机读取的性能上可以提高40%。
关于"-fno-builtin-memcmp"这个选项:
函数名"memcmp"和C语言的内建函数重名了,如果要使用自己的"memcmp"
就要在编译时加入选项"-fno-builtin-自己定义函数名"。
(详细的内容可以见我转载的博客:Gcc编译选项-fno-builtin -fno-builtin-function)
*/
case "$TARGET_OS" in
CYGWIN_*)
PLATFORM=OS_LINUX
COMMON_FLAGS="$MEMCMP_FLAG -lpthread -DOS_LINUX -DCYGWIN"
PLATFORM_LDFLAGS="-lpthread"
PORT_FILE=port/port_posix.cc
;;
Darwin)
PLATFORM=OS_MACOSX
COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX"
PLATFORM_SHARED_EXT=dylib
[ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd`
PLATFORM_SHARED_LDFLAGS="-dynamiclib -install_name $INSTALL_PATH/"
PORT_FILE=port/port_posix.cc
;;
Linux)
PLATFORM=OS_LINUX
COMMON_FLAGS="$MEMCMP_FLAG -pthread -DOS_LINUX"
PLATFORM_LDFLAGS="-pthread"
PORT_FILE=port/port_posix.cc
;;
SunOS)
PLATFORM=OS_SOLARIS
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_SOLARIS"
PLATFORM_LIBS="-lpthread -lrt"
PORT_FILE=port/port_posix.cc
;;
FreeBSD)
PLATFORM=OS_FREEBSD
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_FREEBSD"
PLATFORM_LIBS="-lpthread"
PORT_FILE=port/port_posix.cc
;;
NetBSD)
PLATFORM=OS_NETBSD
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_NETBSD"
PLATFORM_LIBS="-lpthread -lgcc_s"
PORT_FILE=port/port_posix.cc
;;
OpenBSD)
PLATFORM=OS_OPENBSD
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_OPENBSD"
PLATFORM_LDFLAGS="-pthread"
PORT_FILE=port/port_posix.cc
;;
DragonFly)
PLATFORM=OS_DRAGONFLYBSD
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_DRAGONFLYBSD"
PLATFORM_LIBS="-lpthread"
PORT_FILE=port/port_posix.cc
;;
OS_ANDROID_CROSSCOMPILE)
PLATFORM=OS_ANDROID
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_ANDROID -DLEVELDB_PLATFORM_POSIX"
PLATFORM_LDFLAGS=""
# All pthread features are in the Android C library
PORT_FILE=port/port_posix.cc
CROSS_COMPILE=true
;;
HP-UX)
PLATFORM=OS_HPUX
COMMON_FLAGS="$MEMCMP_FLAG -D_REENTRANT -DOS_HPUX"
PLATFORM_LDFLAGS="-pthread"
PORT_FILE=port/port_posix.cc
# man ld: +h internal_name
PLATFORM_SHARED_LDFLAGS="-shared -Wl,+h -Wl,"
;;
IOS)
PLATFORM=IOS
COMMON_FLAGS="$MEMCMP_FLAG -DOS_MACOSX"
[ -z "$INSTALL_PATH" ] && INSTALL_PATH=`pwd`
PORT_FILE=port/port_posix.cc
PLATFORM_SHARED_EXT=
PLATFORM_SHARED_LDFLAGS=
PLATFORM_SHARED_CFLAGS=
PLATFORM_SHARED_VERSIONED=
;;
*)
echo "Unknown platform!" >&2
exit 1
esac
/*
shell中的switch,case结构。
-pthread编译选项是用于在编译时增加多线程的支持。
-DOS_LINUX到底是啥,知道的告诉我一声,十分感谢!
*/
# We want to make a list of all cc files within util, db,
# table, and helpers except for the test and benchmark files.
# By default, find will output a list of all files matching
# either rule, so we need to append -print to make the
# prune take effect.
DIRS="$PREFIX/db $PREFIX/util $PREFIX/table"
/*
列出在util/,db/,table/,helpers/中除了用作test和benchmark的所有
.cc文件。
*/
set -f
# temporarily disable globbing so that our patterns
# aren't expanded
PRUNE_TEST="-name *test*.cc -prune"
PRUNE_BENCH="-name *_bench.cc -prune"
PRUNE_TOOL="-name leveldbutil.cc -prune"
PORTABLE_FILES=`find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o $PRUNE_TOOL -o -name '*.cc' -print | sort | sed "s,^$PREFIX/,," | tr "\n" " "`
set +f # re-e nable globbing
/*
set -f 禁用通配符(我觉得没有什么作用)
find $DIRS $PRUNE_TEST -o $PRUNE_BENCH -o $PRUNE_TOOL -o -name '*.cc' -print | sort|sed "s,^$PREFIX/,,"|tr "\n" " "
上面这句shell命令特别长不好理解
-o是“或”的意思,类似于||
-prune的意思在这里像是判断前面操作的结果
短路计算知道吧!
也就是说只有不符合那面PRUNE_TEST,PRUNE_BENCH,PRUNE_TOOL这几个查找时,才执行最后的-name '*.cc' -print,
所以实际上打印的内容是派出了符合前面几个模式之后的内容
sed "s,^$PREFIX/,,"
S代表用后一对分隔符之间的内容替换前一对分隔内的内容
^代表行首
在这里后一对分隔符,,之间为空,就是删除前一对分隔符,^$PREFIX/,内容。
tr "\n" " " 用空格替换所有\n
set +f 恢复通配符
*/
# The sources consist of the portable files, plus the
# platform-specific port file.
echo "SOURCES=$PORTABLE_FILES $PORT_FILE" >> $OUTPUT
echo "MEMENV_SOURCES=helpers/memenv/memenv.cc" >> $OUTPUT
/*
sources>>$output 把sources的内容附加到$output的文件末尾
">"代表新建并且从定向,如果源文件存在,会被覆盖
">>"代表附加到文件的末尾
*/
if [ "$CROSS_COMPILE" = "true" ]; then
# Cross-compiling; do not try any compilation tests.
true
else
CXXOUTPUT="${TMPDIR}/leveldb_build_detect_platform-cxx.$$"
/*
如果是跨平台编译,啥编译测试也不做。
$$代表执行这个脚本的shell进程ID。
如果不是跨平台编译,可以测试下面的各种情况,并设置参数。
*/
# If -std=c++0x works, use <atomic> as fallback for when
# memory barriers are not available.
$CXX $CXXFLAGS -std=c++0x -x c++ - -o $CXXOUTPUT 2>/dev/null <<EOF
#include <atomic>
int main() {}
EOF
if [ "$?" = 0 ]; then
COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX -DLEVELDB_ATOMIC_PRESENT"
PLATFORM_CXXFLAGS="-std=c++0x"
else
COMMON_FLAGS="$COMMON_FLAGS -DLEVELDB_PLATFORM_POSIX"
fi
/*
如果-std=c++0x起作用,当memory barriers不可用时,就使用<atomic>作为保底。
2>/dev/null
2代表标准错误
/dev/null是黑洞文件 你可以把不想要的信息都定向到这
<<EOF xxxxxx EOF 是作为将xxxxxx内容传输给命令
$?代表上一条命令的执行结果
根据上一条编译命令执行结果设定不同的参数
*/
# Test whether Snappy library is installed
# http://code.google.com/p/snappy/
$CXX $CXXFLAGS -x c++ - -o $CXXOUTPUT 2>/dev/null <<EOF
#include <snappy.h>
int main() {}
EOF
if [ "$?" = 0 ]; then
COMMON_FLAGS="$COMMON_FLAGS -DSNAPPY"
PLATFORM_LIBS="$PLATFORM_LIBS -lsnappy"
fi
/*
测试是否安装了snappy压缩库
根据结果设置不同参数
*/
# Test whether tcmalloc is available
$CXX $CXXFLAGS -x c++ - -o $CXXOUTPUT -ltcmalloc 2>/dev/null <<EOF
int main() {}
EOF
if [ "$?" = 0 ]; then
PLATFORM_LIBS="$PLATFORM_LIBS -ltcmalloc"
fi
/*
测试是否安装了tcmalloc这个工具,他是用于优化C++写的多线程应用。
设置相关参数
*/
rm -f $CXXOUTPUT 2>/dev/null
fi
/*
删除用于测试而生成的临时文件
结束外层循环
*/
PLATFORM_CCFLAGS="$PLATFORM_CCFLAGS $COMMON_FLAGS"
PLATFORM_CXXFLAGS="$PLATFORM_CXXFLAGS $COMMON_FLAGS"
echo "CC=$CC" >> $OUTPUT
echo "CXX=$CXX" >> $OUTPUT
echo "PLATFORM=$PLATFORM" >> $OUTPUT
echo "PLATFORM_LDFLAGS=$PLATFORM_LDFLAGS" >> $OUTPUT
echo "PLATFORM_LIBS=$PLATFORM_LIBS" >> $OUTPUT
echo "PLATFORM_CCFLAGS=$PLATFORM_CCFLAGS" >> $OUTPUT
echo "PLATFORM_CXXFLAGS=$PLATFORM_CXXFLAGS" >> $OUTPUT
echo "PLATFORM_SHARED_CFLAGS=$PLATFORM_SHARED_CFLAGS" >> $OUTPUT
echo "PLATFORM_SHARED_EXT=$PLATFORM_SHARED_EXT" >> $OUTPUT
echo "PLATFORM_SHARED_LDFLAGS=$PLATFORM_SHARED_LDFLAGS" >> $OUTPUT
echo "PLATFORM_SHARED_VERSIONED=$PLATFORM_SHARED_VERSIONED" >> $OUTPUT
/*
设置参数,把所需的参数附加到$OUTPUT文件的末尾
*/