C 在子目录中构建共享库
我正在尝试构建一个使用一些C代码的R包。我有一个C库,它被编译成可执行文件,可以从命令行调用。有一个与之关联的Makefile 我正试图寻找信息,它说 如果要创建并链接到库,请使用 子目录,使用类似 注意创建所有必要的依赖项,因为没有 保证所有 将按特定顺序运行(以及一些CRAN构建机器 使用多个CPU和并行模块) 如果我在我的包中创建了C 在子目录中构建共享库,c,r,makefile,C,R,Makefile,我正在尝试构建一个使用一些C代码的R包。我有一个C库,它被编译成可执行文件,可以从命令行调用。有一个与之关联的Makefile 我正试图寻找信息,它说 如果要创建并链接到库,请使用 子目录,使用类似 注意创建所有必要的依赖项,因为没有 保证所有 将按特定顺序运行(以及一些CRAN构建机器 使用多个CPU和并行模块) 如果我在我的包中创建了src文件夹的新子目录,名为someLibrary,代码和Makefile保持不变,反过来,在我的包的原始Makevars文件中,我会添加上述代码不变,然后,我
src
文件夹的新子目录,名为someLibrary
,代码和Makefile保持不变,反过来,在我的包的原始Makevars
文件中,我会添加上述代码不变,然后,我将能够使用useDynLib
构建要导出的共享库
编辑1: 根据以下信息,我更改了
Makefile
,通过添加
CFLAG = -fPIC -g -O3
LDFLAGS= -shared
但是,这会导致.so
文件不能直接导出到包的libs
目录的问题。如果我将路径硬编码到目标中,那么文件将被发送到包的libs
目录(这都是通过调用R CMD INSTALL myPackage
)
编辑2: 最后,我想知道如何调用共享库,因为它有一个
main()
方法,我可以从命令行可执行文件调用该方法
将其公开到R命名空间
,以便通过调用它的过程是什么
另外,如果我想把最后一个问题单独提出来,请告诉我。callable.c
#include <stdio.h>
int main(int argc, char **argv) {
printf("Hello World\n");
return 0;
}
现在我们有了callable
R通常要求所有C参数都是指针,但如果您的主方法忽略了argc,那么我们可以绕过这个问题。所以要从callable.So调用main,我们可以从R编写一个这样的方法
main <- function() {
dyn.load("callable.so")
out <- .C("main", argc=0, argv="")
}
main原始问题作者在对该问题的评论中提出了一个使用Automake、Libtool和LDADD
链接在一个目录中编译的程序与在第二个目录中编译的共享库的示例这是一个完整、独立、完整的示例,介绍了如何使用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 <stdio.h>
#include "helloworld.h"
void
say_hello (void)
{
printf ("Hello world!\n");
}
最后,B/foo.c
是使用共享库的程序的源代码。它包括库的头文件,并调用say_hello()
编译程序
B/Makefile.am
文件控制库的编译。我们需要使用变量告诉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 = 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
最后,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
测试它
运行:
您应该看到所需的输出:“Hello world!”也许您应该将它们编译成.o
,并将这些.o
放在Makevars
的对象中。如果包装正确,R将链接它们并正确加载它们。您是否调查过使用automake
和libtool
的可能性?我知道GNU Autotools是一个非常重要的解决方案,但它确实可以在一个目录中编译一个共享对象,然后从另一个目录链接到它。@PeterBrett-Peter,谢谢你的评论。我仍然时不时地为此而挣扎。你能发布一个简单的整个工具链的例子来帮助我开始并适应我的目的吗?如果你愿意,我可以在这个问题上加上悬赏@fg nu I今晚将在共享库示例中发布一个最小的hello world,这可能需要一段时间才能完成。赏金总是很感激的!:-)@彼得布莱特得到了赏金!彼得,你知道有什么好消息吗?你能确定这是否适用于R打包和编译基础设施吗?嗨@fg\u nu,我刚刚阅读了一些相关的R文档,我怀疑没有(天哪,编译和打包的东西非常粗糙)。我以后会想办法的!彼得,别担心谢谢你的回答。彼得,我会给你赏金,但不是复选标记,因为我希望花一些时间在你的答案的基础上,让它成为关于R的,因为最初的问题是关于R的。我希望没关系,如果没有,请告诉我。:)你真好!对不起,我不能准确回答你的问题!我一直想回来调查这个问题——我知道其他使用R的人也问过类似的问题——但时间不够……谢谢,这其实是相当有见地的。我会尽量把这个和彼得的答案结合起来,让整个事情顺利进行。
#include <helloworld.h>
int
main (int argc, char **argv)
{
say_hello ();
return 0;
}
# 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
# 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
# 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
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