工具类
查看可执行文件由什么编译器生成
只能在文件中查找一些字串,如果文件被优化过很可能就找不到了。例如:
strings filename | grep GNU
vs中调试MPI程序的设置
微软提供了MPI环境和对应SDK,但是部分参数要这样设置:
命令 | mpiexec |
---|---|
命令参数 | -n 2 "$(TargetPath)" |
附加包含目录 | $(MSMPI_INC);$(MSMPI_INC)\x86 |
git版本库中移除大文件
git将所有的文件都保存在历史中,因此一个大文件如果被加进了版本库中,它就会一直存在。以下脚本可处理这些文件。
脚本1:查找大文件,参数1是个数。里面有一个乱写的临时文件名,如果有人非要用这个名字我也没办法。
# find big files in a git storage
# $1 how much to out put
temp=temp_fv4erkjifriu
git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -$1 | awk '{print $1" " $3}' > $temp
git rev-list --objects --all | grep "`cat $temp | awk '{print $1}'`" | sed `cat $temp | awk '{print "-e s/" $1 "/" $2 "/g" }'` | sort -k 1 -n | awk '{printf "%10d\t%-30s\n", $1, $2}'
rm $temp
脚本2:删除指定文件,参数1是文件名,参数2非零时更新远程版本库。
# remove file(s) from git history
# $1 file(s) name
# $2 1 push after removing
git filter-branch --force --index-filter "git rm --cached --ignore-unmatch $1" --prune-empty --tag-name-filter cat -- --all
if [ $2 == 1 ]; then
rm -rf .git/refs/original/
git reflog expire --expire=now --all
git gc --prune=now
git gc --aggressive --prune=now
git push origin master --force
fi
mpi,openmp并行
mpi是一套消息传递接口,有多种实现。需要下载外部库。
openmpi和mpich最常见,openmpi安装比较简单。如果编译出现链接错误就指定编译器的完整路径。
intelmpi改自mpich。
openmpi自带了scalapack,其他mpi没有。如果一些软件需要用到这个库,可以参考软件本身的设置。
mpi程序在运行的时候,一般会占用对应的核数,每个进程不会超过100%。占用内存会比较大。
openmp是编译器支持的共享内存并行,通常不用特别安装。运行的时候只有一个进程,cpu占用会超过100%。
FFmpeg编译至一个dll
Mingw64下的链接器工作不正常,在linux下用交叉编译。
./configure --cc=i686-w64-mingw32-gcc --cxx=i686-w64-mingw32-g++ --enable-swresample --enable-version3 --disable-symver --disable-doc --disable-ffplay --disable-ffmpeg --disable-ffprobe --disable-ffserver --disable-sdl --disable-zlib --disable-bzlib --disable-lzma --enable-swresample --disable-avfilter --disable-swscale --disable-encoders --target-os=win32 --arch=x86 --enable-cross-compile
i686-w64-mingw32-gcc -shared -o ffmpeg.dll libavutil/*.o libavutil/x86/*.o libavcodec/*.o libavcodec/x86/*.o libavformat/*.o libswresample/*.o libswresample/x86/*.o -lws2_32 -lsecur32 -lm -lpsapi -ladvapi32 -lshell32 -Wl,--enable-runtime-pseudo-reloc -Wl,--disable-auto-image-base -Wl,-Bsymbolic -static-libgcc -static-libstdc++ -Wl,-static -lstdc++ -lpthread -lwinpthread -Wl,--output-def,ffmpeg.def -Wl,--out-implib,ffmpeg.dll.a
i686-w64-mingw32-dlltool -d ffmpeg.def -D ffmpeg.dll -l ffmpeg.lib
i686-w64-mingw32-strip ffmpeg.dll
最后必须要用dlltool生成导出库,否则在vs下链接可能出现非常奇怪的问题。
mingw编译器静态链接
链接时应使用特别的参数,为了避免麻烦,可以将其写入.bashrc。
export LDFLAGS="-static-libgcc -static-libstdc++ -Wl,-static -lstdc++ -lpthread -lwinpthread"
mingw的版本推荐使用MSYS2,用pacman安装mingw-w64-i686-gcc,mingw-w64-x86_64-gcc和相关内容。可以用64位的编译器。
集成cjson进lua的静态库
Windows下:
首先,将cjson的代码都复制到lua的代码中。
这时我们不需要fpconv.c,这个文件中有一些重复的,可以在vs中将这个排除掉。
其次需要以下几处修改:
在c中,inline使用 __inline,因此在需要的地方加上这个宏:
#define inline __inline
vs中snprintf的函数名不一样,在需要的地方加上:
#if _MSC_VER
#define snprintf _snprintf
#endif
vs中字串非大小写敏感比较的函数名不一样,在需要的地方加上:
#ifdef _MSC_VER
#define strcasecmp stricmp
#define strncasecmp strnicmp
#endif
注意实际上前一个宏没有用到。
在fpconv.h的最前面加上:
#define USE_INTERNAL_FPCONV
同时,将cjson注册为lua内部就启动。修改linit.c(黄背景为添加):
static const luaL_Reg loadedlibs[] = {
{"_G", luaopen_base},
{LUA_LOADLIBNAME, luaopen_package},
{LUA_COLIBNAME, luaopen_coroutine},
{LUA_TABLIBNAME, luaopen_table},
{LUA_IOLIBNAME, luaopen_io},
{LUA_OSLIBNAME, luaopen_os},
{LUA_STRLIBNAME, luaopen_string},
{LUA_BITLIBNAME, luaopen_bit32},
{LUA_MATHLIBNAME, luaopen_math},
{LUA_CJSONLIBNAME, luaopen_cjson},
{LUA_DBLIBNAME, luaopen_debug},
{NULL, NULL}
};
修改lualib.h,定义cjson的名:
#define LUA_CJSONLIBNAME "cjson"
LUAMOD_API int (luaopen_cjson)(lua_State *L);
选类似的地方就可以了,仿照其他库的方法。
使用例子:
function f1()
local text = '[ 0.110001, 0.12345678910111, 0.412454033640, 2.6651441426902, 2.718281828459, 3.1415926535898, 2.1406926327793 ]';
local v = cjson.decode(text);
outputfloat(v[2]);
math.random(3);
end
应会输出第二个数字。
静态库中应当排除lua.c,在linux下面,需要注意这时静态库是定制的,最好是换个非默认的名字,否则链接器可能先去查找默认目录下的库。
rapidjson字符串的问题
在rapidjson中,如果需要修改内容,在设置key和value为字符串时,都是传递指针的。这就意味着,一旦某个字串指针在什么地方失效了,rapidjson的内容基本就不正确了。
因此,在大部分时候,应当使用字符指针常量,如果必要时使用std::string,也需要注意在字串生存周期之内,rapidjson才会正确。类似以下的调用其实是不可靠的:
void setKey(const std::string& key, const std::string& value)
{
Addmember(key.c_str(), value.c_str(), _document.GetAllocator());
}
如果调用是传递的是常量字符指针,这个调用含有隐式转换,在函数结束之后,转换得到的std::string会被销毁。如果传递的是std::string,那么一旦原来的字串被销毁,后面的结果也不会可靠。尽管后面有一个分配空间的引用函数,但是这样做是不行的。 应当注意在有字串的时候,为了安全,要先让rapidjson在已经分配的空间制作一个副本。可以这样做:
rapidjson::Document::AllocatorType& _docAlloc()
{
return _document.GetAllocator();
}
const char* allocString(const char* key)
{
rapidjson::Value k(key, _docAlloc());
return k.GetString();
}
上面是为了偷懒,返回一个引用。之后原来的函数应这样使用:
Addmember(allocString(key.c_str()), allocString(value.c_str()), _docAlloc());
Rapidjson好多用法太奇怪了,使用了很多引用和模板,因此有些值是不能作为函数返回值的。这就被迫使用一些不太好看的手段。
编译新版gcc
除非特殊需要,没事不要搞这个。
下载完源码之后,最好新建一个目录,编译中间文件可以和源码不搅在一起。
下载新版的gmp、mpc、mpfr源码,解压放在gcc目录下,要改目录名为前面的样子,不需要版本号。
cloog和isl如果让gcc自己处理总是不正常,推荐自己预先编译好。
isl只支持到0.12,cloog到0.18,更高的版本都不太正常。Isl 1.3以及之后的新版有一个符号会判断错误。
gcc自己处理的话可能会调用automake,但是这个又是一个怪东西,似乎gcc的ac文件是用autoconf 2.64,但是又会调用automake 1.14以上的版本,而automake 1.14必须要autoconf 2.65以上才能编译。这个版本要求形成了一个怪圈。
mkdir build
cd build
../configure --prefix=/usr/local/gcc-4.9.2/ --enable-languages=c,c++ --disable-multilib
make
在编译过程中,可能有几个错误:
-Atmp-attrtab.c -Dtmp-dfatab.c -Ltmp-latencytab.c
make[3]: *** [s-attrtab] Killed
或者
xg++: internal compiler error: Killed (program cc1plus)
这个错误一般是内存不足,建立如下脚本并运行:
#swap.sh
SWAP=/tmp/swap
dd if=/dev/zero of=$SWAP bs=1M count=8000
mkswap $SWAP
sudo swapon $SWAP
注意这个是建立了8G的交换空间,经试验,4G仍然不够。 编译成功后,将这个文件删除。
swapoff /tmp/swap
rm /tmp/swap
最后如果只生成一个gcc,没有g++,可以用gcc –lstdc++来链接。编译使用gcc也可以。 最后,将编译目录中的x86_64-unknown-linux-gnu/libstdc++-v3/src/.libs/libstdc++.so.6.0.20和对应的链接复制到/usr/lib64。可以在/usr/local/bin中用ln –s来创建一个链接。
c++filt
该命令可以将C++编译后的符号表转成原来的形式。例如:
nm xxx.o | c++file