4

我正在尝试使用已下载到 main.cpp 文件文件夹中的samtools C API ( https://github.com/samtools/samtools ) 编译(在 Linux 上,使用 G++)一个简单的 main.cpp 程序。我想要一个非常简单的makefile来编译main.cpp(并最终编译samtools代码)。但是,由于我对 makefile 知之甚少,我可能做错了什么。

这是我的生成文件:

SAMTOOLS=./samtools/
HTSLIB=${SAMTOOLS}htslib-1.9/

all: samtools htslib BAMCoverage

samtools: 
    ${MAKE} -C ${SAMTOOLS}

htslib: 
    ${MAKE} -C ${HTSLIB}

BAMCoverage: main.cpp
    g++ -I./ -I${SAMTOOLS} -I${HTSLIB} -g -O2 -Wall ./main.cpp -o ./BAMCoverage -lz -L${SAMTOOLS} -L${HTSLIB} -lbam  -lhts

这是我的 cpp 主要内容:

#include "samtools/sam.h"

#include <string>
#include <iostream>

using namespace std;

int main (int argc, char *argv[]) { 
    string bam_file_path ("myfile.bam");
    bamFile bam_file = bam_open (bam_file_path.c_str (), "rb");
    if (bam_file == 0) {
        cerr << "Failed to open BAM file " << bam_file_path << endl;
        return 1;
    }
    bam_close (bam_file);

    return 0;
}

当我运行“make”时,它编译时没有警告,但在运行时,它告诉我:“加载共享库时出错:libhts.so.2 无法打开共享对象文件”

任何帮助都非常受欢迎!提前致谢。

4

1 回答 1

2

这不是您的 makefile 本身的问题;您的 makefile 有一些问题,但您遇到的问题是了解如何正确链接共享库。换句话说,如果你从 shell 命令行运行相同的命令集,而不是使用 makefile,你就会遇到同样的问题。

您应该查找有关链接命令行选项的文档,-L并了解链接时库位置和运行时库位置之间的区别。

-lfoo选项将告诉链接器链接到名为foo. 该-Lsome/dir选项将告诉链接器foo在目录中查找该库some_dir

如果链接器找到一个静态库libfoo.a,那么链接您的程序所需的该库的任何部分都将直接包含在您的程序中。这会使您的程序更大,但这意味着在运行时除了您的程序之外,不需要找到任何东西。

如果链接器找到一个共享库(也称为动态库)libfoo.so,那么链接器只需将库名称libfoo.so的引用放入您的程序中(当然细节比这更复杂,但这是一般的想法)。这使您的程序更小,但这意味着在运行时不仅需要您的程序,还需要共享库,否则您的程序将无法运行。

这称为运行时链接,当您启动程序时用于解析所有这些共享引用的程序称为运行时链接器。出于很好的原因,编译时链接器在您的程序中放入的引用仅列出了库的名称,而不是库的完整路径。这意味着运行时链接器需要知道在哪里寻找共享库。

运行时链接器在各个地方查找,可以通过阅读其文档了解;例如,在 GNU/Linux 上调用运行时链接器,ld.so因此您可以使用man ld.so.

这是一个复杂的主题,最好的方法在很大程度上取决于您的需求和要求。

如果您只想硬编码在编译/链接时查看的路径,您可以-Rsome/dir在链接行中添加一个选项,每个-L选项一个,如下所示:

BAMCoverage: main.cpp
        g++ -I./ -I${SAMTOOLS} -I${HTSLIB} -g -O2 -Wall ./main.cpp -o ./BAMCoverage -lz -L${SAMTOOLS} -L${HTSLIB} -R${SAMTOOLS} -R${HTSLIB} -lbam  -lhts

只要SAMTOOLSHTSLIB目录存在并且其中仍然包含正确的共享库,这将正常工作。显然这是一个很大的限制,但我们无法猜测您的最终要求是什么。

于 2018-10-21T17:44:09.297 回答