在子目录中构建共享库

我正在尝试构建一个使用一些C代码的R包。 我有一个C库,它被编译成可执行文件,可以从命令行调用。 有一个与之关联的Makefile。

我试图在这里查看信息

如果要创建然后链接到库,比如使用子目录中的代码,请使用类似的东西

.PHONY: all mylibs all: $(SHLIB) $(SHLIB): mylibs mylibs: (cd subdir; make) 

小心创建所有必需的依赖项,因为无法保证所有依赖项都以特定顺序运行(并且某些CRAN构建机器使用多个CPU和并行产生)。

如果我在我的包中创建一个src文件夹的新子目录,名为someLibrary ,代码和Makefile保持不变,反过来,在我的包的原始Makevars文件中,我将上面的代码保持不变,那么我将能够构建要使用useDynLib导出的共享库?


编辑1:

在这里的信息,我更改了Makefile以通过添加创建共享库

 CFLAG = -fPIC -g -O3 LDFLAGS= -shared 

但是,这会导致.so文件不直接导出到包的libs目录的问题。 如果我硬编码到目标的路径,那么文件将被发送到包的libs目录(这是通过调用R CMD INSTALL myPackage )。


编辑2:

最后,我想知道如何调用共享库,因为它有一个main()方法,我可以从命令行可执行文件中调用它。

将它暴露给R NAMESPACE的过程是什么,以便可以通过.Call调用.Call

PS。 如果我将最后一点作为一个单独的问题,请告诉我。

最初的问题作者在问题的评论中询问了使用AutomakeLibtoolLDADD将一个目录中编译的程序与第二个目录中编译的共享库链接起来的示例。 这是一个完整,独立,完整的示例,说明如何使用GNU Autotools在同一源代码树的不同目录中编译库和程序。

目录结构

我们需要设置一个目录结构如下:

 ├ A/ │ ├ Makefile.am │ ├ helloworld.c │ └ helloworld.h ├ B/ │ ├ Makefile.am │ └ foo.c ├ configure.ac └ Makefile.am 

共享库将在目录A/编译,以及在目录B/中使用它的程序。

编写源代码

有三个源文件。

A/helloworld.c是库的源代码。 它导出一个过程say_hello() ,它打印消息“Hello world!” 到标准输出。

 #include  #include "helloworld.h" void say_hello (void) { printf ("Hello world!\n"); } 

A/helloworld.h是头文件,包含say_hello()函数的声明。 它只有一行:

 void say_hello (void); 

最后, B/foo.c是使用共享库的程序的源代码。 它包含库的头文件,并调用say_hello()

 #include  int main (int argc, char **argv) { say_hello (); return 0; } 

编译库

我们将使用Automake和Libtool来编译共享库。 这两种工具都非常强大,而且实际上有很好的文档记录。 手册( Automake , Libtool )绝对值得一读。

automake使用A/Makefile.am文件来控制库的编译。

 # We're going to compile one libtool library, installed to ${libdir}, # and named libhelloworld. lib_LTLIBRARIES = libhelloworld.la # List the source files used by libhelloworld. libhelloworld_la_SOURCES = helloworld.c # We install a single header file to ${includedir} include_HEADERS = helloworld.h 

编译程序

B/Makefile.am文件控制库的编译。 我们需要使用LDADD变量来告诉automake链接我们之前编译的库。

 # Compile one program, called foo, and installed to ${bindir}, with a single C # source file. bin_PROGRAMS = foo foo_SOURCES = foo.c # Link against our uninstalled copy of libhelloworld. LDADD = $(top_builddir)/A/libhelloworld.la # Make sure we can find the uninstalled header file. AM_CPPFLAGS = -I$(top_srcdir)/A 

控制构建

最后,我们需要一个顶级的Makefile.am来告诉Automake如何构建项目,以及一个configure.ac文件来告诉Autoconf如何找到所需的工具。

顶级的Makefile.am非常简单:

 # Compile two subdirectories. We need to compile A/ first so the shared library is # available to link against. SUBDIRS = AB # libtool requires some M4 scripts to be added to the source tree. Make sure that # Autoconf knows where to find them. ACLOCAL_AMFLAGS = -I m4 

最后, configure.ac文件告诉Autoconf如何创建configure脚本。

 AC_INIT([libhelloworld], 1, peter@peter-b.co.uk) # This is used to help configure check whether the source code is actually present, and # that it isn't being run from some random directory. AC_CONFIG_SRCDIR([A/helloworld.c]) # Put M4 macros in the m4/ subdirectory. AC_CONFIG_MACRO_DIR([m4]) # We're using automake, but we want to turn off complaints about missing README files # etc., so we need the "foreign" option. AM_INIT_AUTOMAKE([foreign]) # We need a C compiler AC_PROG_CC # Find the tools etc. needed by libtool AC_PROG_LIBTOOL # configure needs to generate three Makefiles. AC_CONFIG_FILES([A/Makefile B/Makefile Makefile]) AC_OUTPUT 

测试出来

跑:

 $ autoreconf -i $ ./configure $ make $ B/foo 

您应该看到所需的输出:“Hello world!”

callable.c

 #include  int main(int argc, char **argv) { printf("Hello World\n"); return 0; } 

要从C文件callable.c中获取.so文件,请使用

 R CMD SHLIB callable.c 

所以现在我们有callable.so

R通常要求所有C参数都是指针,但如果你的main方法忽略了argc,那么我们可以解决这个问题。 因此,要从R调用main来自callable.so,我们可以编写一个这样的方法。

 main <- function() { dyn.load("callable.so") out <- .C("main", argc=0, argv="") } 

调用main函数将运行C main函数。