如何访问和使用共享库中定义的字符串
How to access & use string defined in shared library
我正在尝试将版本字符串烘焙到共享库中,但无法弄清楚如何在库的客户端程序中访问该字符串。
我想使用的方法是:将版本字符串放在文本文件 version.txt
中,使用 objcopy
将其转换为目标文件,link 将其转换为.so
和link针对动态共享库的客户端程序。
这是我的代码。
version.txt
1.2.3.4
test.cpp
#include <iostream>
extern size_t _binary_version_txt_size;
int main() { std::cout << "Size: " << _binary_version_txt_size << std::endl; }
生成文件
# abbreviate the tools we'll use
CXX:=g++-8
OC:=objcopy
# set up the compile and link options
CXXFLAGS:=-std=c++17 -Wall -pedantic -fPIC -g
# identify phony targets
.PHONY: clean
# set the default targets
all: test
# recipe to convert text files to object files
%.o: %.txt
$(OC) --input binary --output elf64-x86-64 --binary-architecture i386:x86-64 $< $@
# recipes for building objects from source files
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -c -o $@
# recipe to build shared lib
libtest.so: version.o
$(CXX) $(CXXFLAGS) $^ -shared -o $@
# recipe to build the target executable
test: test.o libtest.so
$(CXX) $(CXXFLAGS) $< -L. -ltest -o $@
# recipe to clean up after ourselves
clean:
rm -f *.o test
我期望的符号在库中:
$ nm libtest.so | grep version
0000000000201027 D _binary_version_txt_end
0000000000000007 A _binary_version_txt_size
0000000000201020 D _binary_version_txt_start
但是,我从 linker 那里得到这个警告:
/usr/bin/ld: warning: type and size of dynamic symbol `_binary_version_txt_size' are not defined
程序运行时打印出错误的符号值:
$ LD_LIBRARY_PATH=$(pwd) ./test
Size: 0 <- expected 7
这是 dlsym
或 extern "C"
的工作,还是指定了 -E
link 等选项?我有几个 w/o 成功。
谢谢!
所以,我找到了“我的方式”,但仍然认为 Lorinczy 的方法更好。
我最终放弃了读取字符串大小的尝试,并想出了这段运行良好的代码:
#define DATASTRING(NAME) \
[]() -> std::string { \
extern char _binary_##NAME##_txt_start[]; \
extern char _binary_##NAME##_txt_end[]; \
size_t sz = _binary_##NAME##_txt_end - _binary_##NAME##_txt_start; \
std::string ans(_binary_##NAME##_txt_start, sz); \
ans.pop_back(); \
return ans; \
}()
用法示例
std::string version = DATASTRING(version);
我学到的其他东西:
- 至少在这种情况下
char[]
与 char*
不同。
- 链接到二进制文件中的字符串不是空终止的,您需要知道它们的大小或长度。
我正在尝试将版本字符串烘焙到共享库中,但无法弄清楚如何在库的客户端程序中访问该字符串。
我想使用的方法是:将版本字符串放在文本文件 version.txt
中,使用 objcopy
将其转换为目标文件,link 将其转换为.so
和link针对动态共享库的客户端程序。
这是我的代码。
version.txt
1.2.3.4
test.cpp
#include <iostream>
extern size_t _binary_version_txt_size;
int main() { std::cout << "Size: " << _binary_version_txt_size << std::endl; }
生成文件
# abbreviate the tools we'll use
CXX:=g++-8
OC:=objcopy
# set up the compile and link options
CXXFLAGS:=-std=c++17 -Wall -pedantic -fPIC -g
# identify phony targets
.PHONY: clean
# set the default targets
all: test
# recipe to convert text files to object files
%.o: %.txt
$(OC) --input binary --output elf64-x86-64 --binary-architecture i386:x86-64 $< $@
# recipes for building objects from source files
%.o: %.cpp
$(CXX) $(CXXFLAGS) $< -c -o $@
# recipe to build shared lib
libtest.so: version.o
$(CXX) $(CXXFLAGS) $^ -shared -o $@
# recipe to build the target executable
test: test.o libtest.so
$(CXX) $(CXXFLAGS) $< -L. -ltest -o $@
# recipe to clean up after ourselves
clean:
rm -f *.o test
我期望的符号在库中:
$ nm libtest.so | grep version
0000000000201027 D _binary_version_txt_end
0000000000000007 A _binary_version_txt_size
0000000000201020 D _binary_version_txt_start
但是,我从 linker 那里得到这个警告:
/usr/bin/ld: warning: type and size of dynamic symbol `_binary_version_txt_size' are not defined
程序运行时打印出错误的符号值:
$ LD_LIBRARY_PATH=$(pwd) ./test
Size: 0 <- expected 7
这是 dlsym
或 extern "C"
的工作,还是指定了 -E
link 等选项?我有几个 w/o 成功。
谢谢!
所以,我找到了“我的方式”,但仍然认为 Lorinczy 的方法更好。
我最终放弃了读取字符串大小的尝试,并想出了这段运行良好的代码:
#define DATASTRING(NAME) \
[]() -> std::string { \
extern char _binary_##NAME##_txt_start[]; \
extern char _binary_##NAME##_txt_end[]; \
size_t sz = _binary_##NAME##_txt_end - _binary_##NAME##_txt_start; \
std::string ans(_binary_##NAME##_txt_start, sz); \
ans.pop_back(); \
return ans; \
}()
用法示例
std::string version = DATASTRING(version);
我学到的其他东西:
- 至少在这种情况下
char[]
与char*
不同。 - 链接到二进制文件中的字符串不是空终止的,您需要知道它们的大小或长度。