前段时间给同事们做的一个training,简单介绍C++11里的智能指针,反正没有机密信息,完全可以公开分享,就放这儿吧。
主要内容:
- std::shared_ptr
- std::unique_ptr
- std::weak_ptr
- std::enable_shared_from_this
- array相关
- 其它
前段时间给同事们做的一个training,简单介绍C++11里的智能指针,反正没有机密信息,完全可以公开分享,就放这儿吧。
主要内容:
前段时间遇到一个问题,如果有多个动态链接库同时link另外一个静态链接库,这个静态库里的全局变量(或者static变量)会怎么样呢?
拍脑袋想想,总共也就这么几种可能:
仔细想想,分析一下,各种可能性都有,得看这些库和可执行文件是怎么编译链接的才行,具体看下面的各种case。
同时,测试的code里在dynamic里加上了同名的函数,看看函数会有什么表现。
假设有如下文件(code见Gist):
common.h common.cpp // 生成libcommon.a dynamic1.h dynami1.cpp // 生成libdynamic1.so dynamic2.h dynamic2.cpp // 生成libdynamic2.so main.cpp // 生成main
生成libcommon.a
总是这么编译:
g++ -g -Wall -Wextra -c -o common.o common.cpp ar rcs libcommon.a common.o
g++ -g -Wall -Wextra -fPIC -shared -o libdynamic1.so dynamic1.cpp g++ -g -Wall -Wextra -fPIC -shared -o libdynamic2.so dynamic2.cpp g++ -DDIRECT_CALL_SO -o main main.cpp -L. -ldynamic1 -ldynamic2
这种情况结果显然是4,link时出错,找不到.a里的函数。
g++ -g -Wall -Wextra -fPIC -shared -o libdynamic1.so dynamic1.cpp g++ -g -Wall -Wextra -fPIC -shared -o libdynamic2.so dynamic2.cpp g++ -DDIRECT_CALL_SO -o main main.cpp -L. -ldynamic1 -ldynamic2 -lcommon LD_LIBRARY_PATH=. ./main
这种情况下执行的结果是2,link时没错,执行时看到的也是同一个变量。
GetInt()
返回值是1,它依赖于-l的顺序,如果-ldynamic2
在前,返回值就是2了。
g++ -g -Wall -Wextra -fPIC -shared -o libdynamic1.so dynamic1.cpp -L. -lcommon g++ -g -Wall -Wextra -fPIC -shared -o libdynamic2.so dynamic2.cpp -L. -lcommon g++ -DDIRECT_CALL_SO -o main main.cpp -L. -ldynamic1 -ldynamic2 LD_LIBRARY_PATH=. ./main
执行结果同上
dlopen()
调用so,无所谓链接.a
g++ -g -Wall -Wextra -fPIC -shared -o libdynamic1.so dynamic1.cpp g++ -g -Wall -Wextra -fPIC -shared -o libdynamic2.so dynamic2.cpp g++ -o main main.cpp -ldl [-L. -lcommon] LD_LIBRARY_PATH=. ./main
执行结果是4,dlopen
的时候找不到 GetGlobalStatic()
。
dlopen()
调用so(不用RTLD_GLOBAL
),无所谓链接.a
g++ -g -Wall -Wextra -fPIC -shared -o libdynamic1.so dynamic1.cpp -L. -lcommon g++ -g -Wall -Wextra -fPIC -shared -o libdynamic2.so dynamic2.cpp -L. -lcommon g++ -o main main.cpp -ldl LD_LIBRARY_PATH=. ./main
执行结果是3,各有各自的变量。
GetInt()
返回的也是各自的变量。
dlopen()
调用so(使用RTLD_GLOBAL
),无所谓链接.a
g++ -g -Wall -Wextra -fPIC -shared -o libdynamic1.so dynamic1.cpp -L. -lcommon g++ -g -Wall -Wextra -fPIC -shared -o libdynamic2.so dynamic2.cpp -L. -lcommon g++ -DUSE_RTLD_GLOBAL -o main main.cpp -ldl -L. -lcommon LD_LIBRARY_PATH=. ./main
执行结果变成2了,执行时看到了同一个变量。
GetInt()
返回的仍然是各自的变量。
看了这么多case,结果1怎么没有出现呢?别急,如果编译的时候全部编译在一起:
g++ -DDIRECT_CALL_SO -o main main.cpp dynamic1.cpp dynamic2.cpp common.cpp
就出错了,GetInt()
重定义。
结论
dlopen()
的flag:
RTLD_LOCAL
(默认),各个so会使用各自的.a里的变量。RTLD_GLOBAL
,就跟直接link一样,用同一个变量了。一般来说,Calibre Recipe关注的内容是定期更新的,比如说知乎日报的内容,文章列表每天都会全部更新。
但如果某些内容并不是完全更新,只是部分更新,怎么处理呢?
比如说简书的每周热门文章,某些文章因为热门会持续几周都在其中。这样的话Recipe应该怎么处理才能保证只抓取新的文章,而忽略以前收录的文章呢?
一个朴素的想法就是,把之前收录过的文章都保存起来,然后在recipe里添加要抓取文章之前先check一下有没有抓取过了。
然而在尝试这个朴素的想法的时候,发现在Recipe里保存数据是个问题——保存的文件找不到!
稍微debug了一下,然后看了一下calibre的实现,发现它在抓取过程中的working directory是`/tmp/`下的一个临时目录,完成之后还会被删掉,当然找不到了。。。
尝试一:绝对路径,它work,但是太丑了。
尝试二:如下python里一般获取cwd的方法都不work
os.getcwd() print os.path.dirname(os.path.realpath(__file__))
因为calibre在__init__.py里有`self.cwd = None` 然后`os.chdir()`
尝试三:遍历inpsect一层层的stack,结果只能找到`/usr/bin/`里面去
尝试四:最后突然想到,既然只是个环境变量,那在os.environ里一定有相关的信息嘛,直接打印看一下,发现
os.environ['PWD']
就是我想要的目录。于是,用这个目录当CWD就搞定了。
具体的code直接看这个commit了。