使用 Makefile 中的头文件编译 Pybind(不使用 cmake)
Compile Pybind with header files in Makefile (not using cmake)
我正在尝试在 C++
中编译一个 Pybind11
模块,它在顶部调用几个头文件 (.h)
。因为我有很多头文件,所以我决定做一个 Makefile
,除了创建目标共享对象文件 (s.o)
之外,它没有问题。我需要这个共享对象文件以便能够调用 Python 中的 Pybind 模块。
然而,在编译时,我得到:
g++ -shared -fPIC neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o population.o example.o -o example.so
/usr/bin/ld: example.o: relocation R_X86_64_PC32 against symbol `_ZTI3Pet' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'example.so' failed
make: *** [example.so] Error 1
我的问题基本上是:在编译目标文件以创建目标时我做错了什么?
任何帮助将不胜感激。预先感谢您的回复。
生成文件
example.so: neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o population.o example.o
g++ neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o population.o example.o -shared -o example.so
neat.o: neat.cpp neat.h
g++ -c -O3 -Wall -fPIC neat.cpp
network.o: network.cpp network.h
g++ -c -O3 -Wall -fPIC network.cpp
nnode.o: nnode.cpp nnode.h
g++ -c -O3 -Wall -fPIC nnode.cpp
link.o: link.cpp link.h
g++ -c -O3 -Wall -fPIC link.cpp
trait.o: trait.cpp trait.h
g++ -c -O3 -Wall -fPIC trait.cpp
gene.o: gene.cpp gene.h
g++ -c -O3 -Wall -fPIC gene.cpp
innovation.o: innovation.cpp innovation.h
g++ -c -O3 -Wall -fPIC innovation.cpp
organism.o: organism.cpp organism.h genome.h genome.cpp species.h species.cpp
g++ -c -O3 -Wall -fPIC organism.cpp
species.o: species.h species.cpp organism.cpp organism.h genome.h genome.cpp
g++ -c -O3 -Wall -fPIC species.cpp
genome.o: genome.cpp genome.h
g++ -c -O3 -Wall -fPIC genome.cpp
population.o: population.cpp population.h organism.h
g++ -c -O3 -Wall -fPIC population.cpp
experiments.o: experiments.cpp experiments.h
g++ -c -O3 -Wall -fPIC experiments.cpp
example.o:
g++ -O3 -Wall -std=c++11 -fopenmp -I -fPIC `python3 -m pybind11 --includes` -c example.cpp
clean:
rm *.o *.so
example.cpp
#include <pybind11/pybind11.h>
#include <iostream>
#include <string>
#include "population.h"
namespace py = pybind11;
int create_neat(){
Population *the_pop=0;
return 0;
}
PYBIND11_MODULE(example, m){
m.def("create_neat", &create_neat, "create a pop object");
}
该标准没有完全定义 #include "..."
和 #include <...>
之间的区别,但在所有编译器中,我熟悉的 <>
语法包含通常意味着,"this is a system-type header file" 和 ""
语法表示 "this is a local-type header file".
实际上这通常意味着 ""
在工作目录中查找,然后在编译器的 -I
选项指定的目录中查找,最后在系统默认目录中查找,而 <>
是一样的,只是它不在工作目录中查找。
因此,您需要更改代码才能使用:
#include "population.h"
否则您需要将 -I.
添加到您的编译行以便编译器知道在当前目录中查找:
population.o: population.cpp population.h organism.h
g++ -I. -c population.cpp
我个人会两者都做,因为将你需要的目录添加到你的编译行是一种很好的卫生习惯,并且因为对本地 header 使用 ""
是一种很好的做法,所以阅读代码立即明白这是你的 header 而不是系统 header.
关于你的第二个问题,为了与 object 文件共享 object 文件而进行的编译是否正确 对不起,但我不明白你在问什么。
如果您询问的是 makefile 中定义的目标的顺序,那么它们可以是任何顺序除了第一个目标将是默认目标(如果您 运行 make
没有目标名称,那么 make 将构建第一个目标——以及第一个目标所需的任何先决条件。
预计到达时间
OK,现在我们可以看到实际的错误是 example.o
不存在。为什么不存在?同样,因为您已经从问题示例中删除了重要细节,所以我们无法确定。当你写下你的问题时:
example.so: //some .o files which are not important// HERE IS THE PROBLEM
作为 example.so
的先决条件出现的 .o
文件到底是什么?
如果您想在尝试构建 example.so
之前构建 example.o
,则必须将文件 example.o
列为 example.so
的先决条件。您需要列出创建共享库所需的 所有 object 个文件。所以这应该是:
example.so: population.o example.o neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o
它们在先决条件列表中出现的顺序无关紧要,但它们必须全部存在。
经过几个小时的阅读、尝试以及多亏了 MadScientist 的提示,我让它工作了,但原因仍然不清楚。我只是通过将 -shared -o example.so
放在前面而不是行尾来更改目标编译中先决条件的顺序,并且它起作用了。
整个文件如下:
example.so: neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o population.o example.o
g++ -shared -o example.so neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o population.o example.o
neat.o: neat.cpp neat.h
g++ -c -O3 -Wall -fPIC neat.cpp
network.o: network.cpp network.h
g++ -c -O3 -Wall -fPIC network.cpp
nnode.o: nnode.cpp nnode.h
g++ -c -O3 -Wall -fPIC nnode.cpp
link.o: link.cpp link.h
g++ -c -O3 -Wall -fPIC link.cpp
trait.o: trait.cpp trait.h
g++ -c -O3 -Wall -fPIC trait.cpp
gene.o: gene.cpp gene.h
g++ -c -O3 -Wall -fPIC gene.cpp
innovation.o: innovation.cpp innovation.h
g++ -c -O3 -Wall -fPIC innovation.cpp
organism.o: organism.cpp organism.h genome.h genome.cpp species.h species.cpp
g++ -c -O3 -Wall -fPIC organism.cpp
species.o: species.h species.cpp organism.cpp organism.h genome.h genome.cpp
g++ -c -O3 -Wall -fPIC species.cpp
genome.o: genome.cpp genome.h
g++ -c -O3 -Wall -fPIC genome.cpp
population.o: population.cpp population.h organism.h
g++ -c -O3 -Wall -fPIC population.cpp
experiments.o: experiments.cpp experiments.h
g++ -c -O3 -Wall -fPIC experiments.cpp
example.o:
g++ -O3 -Wall -std=c++11 -fopenmp `python3 -m pybind11 --includes` -fPIC -c example.cpp
clean:
rm *.o *.so
我正在尝试在 C++
中编译一个 Pybind11
模块,它在顶部调用几个头文件 (.h)
。因为我有很多头文件,所以我决定做一个 Makefile
,除了创建目标共享对象文件 (s.o)
之外,它没有问题。我需要这个共享对象文件以便能够调用 Python 中的 Pybind 模块。
然而,在编译时,我得到:
g++ -shared -fPIC neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o population.o example.o -o example.so
/usr/bin/ld: example.o: relocation R_X86_64_PC32 against symbol `_ZTI3Pet' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: Bad value
collect2: error: ld returned 1 exit status
Makefile:2: recipe for target 'example.so' failed
make: *** [example.so] Error 1
我的问题基本上是:在编译目标文件以创建目标时我做错了什么?
任何帮助将不胜感激。预先感谢您的回复。
生成文件
example.so: neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o population.o example.o
g++ neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o population.o example.o -shared -o example.so
neat.o: neat.cpp neat.h
g++ -c -O3 -Wall -fPIC neat.cpp
network.o: network.cpp network.h
g++ -c -O3 -Wall -fPIC network.cpp
nnode.o: nnode.cpp nnode.h
g++ -c -O3 -Wall -fPIC nnode.cpp
link.o: link.cpp link.h
g++ -c -O3 -Wall -fPIC link.cpp
trait.o: trait.cpp trait.h
g++ -c -O3 -Wall -fPIC trait.cpp
gene.o: gene.cpp gene.h
g++ -c -O3 -Wall -fPIC gene.cpp
innovation.o: innovation.cpp innovation.h
g++ -c -O3 -Wall -fPIC innovation.cpp
organism.o: organism.cpp organism.h genome.h genome.cpp species.h species.cpp
g++ -c -O3 -Wall -fPIC organism.cpp
species.o: species.h species.cpp organism.cpp organism.h genome.h genome.cpp
g++ -c -O3 -Wall -fPIC species.cpp
genome.o: genome.cpp genome.h
g++ -c -O3 -Wall -fPIC genome.cpp
population.o: population.cpp population.h organism.h
g++ -c -O3 -Wall -fPIC population.cpp
experiments.o: experiments.cpp experiments.h
g++ -c -O3 -Wall -fPIC experiments.cpp
example.o:
g++ -O3 -Wall -std=c++11 -fopenmp -I -fPIC `python3 -m pybind11 --includes` -c example.cpp
clean:
rm *.o *.so
example.cpp
#include <pybind11/pybind11.h>
#include <iostream>
#include <string>
#include "population.h"
namespace py = pybind11;
int create_neat(){
Population *the_pop=0;
return 0;
}
PYBIND11_MODULE(example, m){
m.def("create_neat", &create_neat, "create a pop object");
}
该标准没有完全定义 #include "..."
和 #include <...>
之间的区别,但在所有编译器中,我熟悉的 <>
语法包含通常意味着,"this is a system-type header file" 和 ""
语法表示 "this is a local-type header file".
实际上这通常意味着 ""
在工作目录中查找,然后在编译器的 -I
选项指定的目录中查找,最后在系统默认目录中查找,而 <>
是一样的,只是它不在工作目录中查找。
因此,您需要更改代码才能使用:
#include "population.h"
否则您需要将 -I.
添加到您的编译行以便编译器知道在当前目录中查找:
population.o: population.cpp population.h organism.h
g++ -I. -c population.cpp
我个人会两者都做,因为将你需要的目录添加到你的编译行是一种很好的卫生习惯,并且因为对本地 header 使用 ""
是一种很好的做法,所以阅读代码立即明白这是你的 header 而不是系统 header.
关于你的第二个问题,为了与 object 文件共享 object 文件而进行的编译是否正确 对不起,但我不明白你在问什么。
如果您询问的是 makefile 中定义的目标的顺序,那么它们可以是任何顺序除了第一个目标将是默认目标(如果您 运行 make
没有目标名称,那么 make 将构建第一个目标——以及第一个目标所需的任何先决条件。
预计到达时间
OK,现在我们可以看到实际的错误是 example.o
不存在。为什么不存在?同样,因为您已经从问题示例中删除了重要细节,所以我们无法确定。当你写下你的问题时:
example.so: //some .o files which are not important// HERE IS THE PROBLEM
作为 example.so
的先决条件出现的 .o
文件到底是什么?
如果您想在尝试构建 example.so
之前构建 example.o
,则必须将文件 example.o
列为 example.so
的先决条件。您需要列出创建共享库所需的 所有 object 个文件。所以这应该是:
example.so: population.o example.o neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o
它们在先决条件列表中出现的顺序无关紧要,但它们必须全部存在。
经过几个小时的阅读、尝试以及多亏了 MadScientist 的提示,我让它工作了,但原因仍然不清楚。我只是通过将 -shared -o example.so
放在前面而不是行尾来更改目标编译中先决条件的顺序,并且它起作用了。
整个文件如下:
example.so: neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o population.o example.o
g++ -shared -o example.so neat.o network.o nnode.o link.o trait.o gene.o innovation.o organism.o species.o genome.o population.o example.o
neat.o: neat.cpp neat.h
g++ -c -O3 -Wall -fPIC neat.cpp
network.o: network.cpp network.h
g++ -c -O3 -Wall -fPIC network.cpp
nnode.o: nnode.cpp nnode.h
g++ -c -O3 -Wall -fPIC nnode.cpp
link.o: link.cpp link.h
g++ -c -O3 -Wall -fPIC link.cpp
trait.o: trait.cpp trait.h
g++ -c -O3 -Wall -fPIC trait.cpp
gene.o: gene.cpp gene.h
g++ -c -O3 -Wall -fPIC gene.cpp
innovation.o: innovation.cpp innovation.h
g++ -c -O3 -Wall -fPIC innovation.cpp
organism.o: organism.cpp organism.h genome.h genome.cpp species.h species.cpp
g++ -c -O3 -Wall -fPIC organism.cpp
species.o: species.h species.cpp organism.cpp organism.h genome.h genome.cpp
g++ -c -O3 -Wall -fPIC species.cpp
genome.o: genome.cpp genome.h
g++ -c -O3 -Wall -fPIC genome.cpp
population.o: population.cpp population.h organism.h
g++ -c -O3 -Wall -fPIC population.cpp
experiments.o: experiments.cpp experiments.h
g++ -c -O3 -Wall -fPIC experiments.cpp
example.o:
g++ -O3 -Wall -std=c++11 -fopenmp `python3 -m pybind11 --includes` -fPIC -c example.cpp
clean:
rm *.o *.so