C++动态库环境变量的传递
Posted 李迟
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++动态库环境变量的传递相关的知识,希望对你有一定的参考价值。
本文研究C++中应用程序和动态库关于环境变量传递的问题。
问题提出
某工程使用到一动态库,内部通过环境变量来控制是否打印某些执行过程的日志。该工程程序在很多机器上运行正常。但笔者机器上无法达到预期,为了研究这个问题,基于以前的动态库工程,以重现问题。
工程代码
工程比较简单,分应用程序和动态库,但源码在同一目录,只是通过 Makefile 编译得到不同的目标文件。在应用程序使用setenv
设置环境变量,动态库内使用getenv
获取环境变量,再修改,最后应用程序读取。
动态库的加载使用dlopen
函数,调用函数使用dlsym
,这样能分离动态库,编译应用程序时不需要依赖so文件 。
所有工程源码如下。
dl.h头文件:
#ifndef DL_H
#define DL_H
#ifdef __cplusplus
extern "C"
#endif
// 使用结构体管理库函数
typedef struct
const char *name; // 名称
// 函数
int (*GetVersion)(char *version);
int (*Foo)();
int (*Bar)();
DL_API_t;
// 单独的函数
int foo();
int bar();
int env_test();
extern DL_API_t gAPI;
#ifdef __cplusplus
#endif
#endif
dl.cpp实现代码:
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "dl.h"
int GetVersion(char *version)
int ver = 10;
sprintf(version, "ver: 0.%d", ver);
return 0;
int Foo()
printf("Foo...\\n");
return 0;
int Bar()
printf("Bar...\\n");
return 0;
DL_API_t gAPI =
.name = "MyLib",
GetVersion,
Foo,
Bar,
;
///
int foo()
printf("foo...\\n");
return 0;
int bar()
printf("bar...\\n");
return 0;
int env_test()
printf("get env in so lib...\\n");
char* value = getenv("FOOBAR");
printf("FOOBAR: %s\\n", value); // 不存在的环境变量
value = getenv("FOO");
printf("FOO: %s\\n", value);
value = getenv("BAR");
printf("BAR: %s\\n", value);
setenv("BAR", "bar 250", 1);
return 0;
测试代码:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <dlfcn.h>
#include <string.h>
#include <errno.h>
#include "dl.h"
typedef int (*pfoo_t)();
pfoo_t pfoo;
int mysetenv(const char* env, const char* value)
if(setenv(env, value, 1) != 0)
printf("setenv %s failed %d: %s\\n", env, errno, strerror(errno));
return 0;
int main(void)
void* handle = NULL;
char version[64] = 0;
printf("so test...\\n");
DL_API_t* aLib = NULL;
// 在加载动态库前设置
//mysetenv("FOO", "foo");
//mysetenv("BAR", "bar");
handle = dlopen("./libfoobar.so", RTLD_LAZY); // 必须加路径
if (handle == NULL)
printf("open failed.\\n");
return -1;
aLib = (DL_API_t*)dlsym(handle, "gAPI");
if (!aLib)
printf("dlsym failed: %s\\n", dlerror());
return -1;
aLib->GetVersion(version);
printf("ver: %s\\n", version);
/*
if (aLib->Foo)
aLib->Foo();
// 另一方式
pfoo = (pfoo_t)dlsym(handle, "foo");
if (pfoo)
pfoo();
// 注:foo和bar的形式一样,可复用指针
pfoo = (pfoo_t)dlsym(handle, "bar");
if (pfoo)
pfoo();
*/
mysetenv("FOO", "foo");
mysetenv("BAR", "bar");
// 注:复用指针
pfoo = (pfoo_t)dlsym(handle, "env_test");
if (pfoo)
pfoo();
char* value = getenv("BAR");
printf("BAR in main: %s\\n", value);
dlclose(handle);
return 0;
原始工程是为了测试动态库存在不同版本的接口函数的,现加了环境变量的测试。
测试
测试结果:
$ ./a.out
so test...
ver: ver: 0.10
get env in so lib...
FOOBAR: (null)
FOO: foo
BAR: bar
BAR in main: bar 250
从结果看出,应用程序和动态库之间是可以通过环境变量传递数据的。
小结
当初发现问题时做了尝试,先在命令行中设置好环境变量,然后再运行程序,是没问题。后和晨哥昌哥讨论,猜测需要在动态库加载之前设置环境变量,后测试果然如是。而在上述代码测试中,不管在哪个阶段设置环境变量,都没问题。这其中有什么玄机,暂时不得而知。
本来想在 golang 和 C++ 程序中使用环境变量交互数据的,但测试后发现也是不行。所以放弃了。
以上是关于C++动态库环境变量的传递的主要内容,如果未能解决你的问题,请参考以下文章