在子目录中构建共享库

tch*_*rty 16 c makefile r

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

我试图神交的信息在这里,它说:

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

 .PHONY: all mylibs

 all: $(SHLIB)
 $(SHLIB): mylibs

 mylibs:
         (cd subdir; make) 
Run Code Online (Sandbox Code Playgroud)

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

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


编辑1:

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

CFLAG = -fPIC -g -O3 
LDFLAGS= -shared
Run Code Online (Sandbox Code Playgroud)

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


编辑2:

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

将此公开给R的程序是什么NAMESPACE,以便可以通过.Call

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

Pet*_*ett 13

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

目录结构

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

? A/
? ? Makefile.am
? ? helloworld.c
? ? helloworld.h
? B/
? ? Makefile.am
? ? foo.c
? configure.ac
? Makefile.am
Run Code Online (Sandbox Code Playgroud)

共享库将在目录中编译A/,并在目录中使用它B/.

编写源代码

有三个源文件.

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

#include <stdio.h>
#include "helloworld.h"

void
say_hello (void)
{
  printf ("Hello world!\n");
}
Run Code Online (Sandbox Code Playgroud)

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

void say_hello (void);
Run Code Online (Sandbox Code Playgroud)

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

#include <helloworld.h>

int
main (int argc, char **argv)
{
  say_hello ();
  return 0;
}
Run Code Online (Sandbox Code Playgroud)

编译库

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

A/Makefile.am文件用于automake控制库的编译.

# 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
Run Code Online (Sandbox Code Playgroud)

编译程序

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
Run Code Online (Sandbox Code Playgroud)

控制构建

最后,我们需要一个顶级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 = A B

# 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
Run Code Online (Sandbox Code Playgroud)

最后,该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
Run Code Online (Sandbox Code Playgroud)

测试出来

跑:

$ autoreconf -i
$ ./configure
$ make
$ B/foo
Run Code Online (Sandbox Code Playgroud)

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


lth*_*eed 2

可调用.c

#include <stdio.h>

int main(int argc, char **argv) {
    printf("Hello World\n");
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

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

R CMD SHLIB callable.c
Run Code Online (Sandbox Code Playgroud)

现在我们有了 callable.so

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

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

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