工具类

查看可执行文件由什么编译器生成

只能在文件中查找一些字串,如果文件被优化过很可能就找不到了。例如:

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

results matching ""

    No results matching ""