在子目录中构建共享库 [英] Building shared libraries in subdirectories
问题描述
我正在尝试构建一个使用某些C代码的R包.我有一个C库,可以将其编译为可执行文件,可以从命令行调用它.有一个与其关联的Makefile.
I am trying to build an R package that uses some C code. I have a C library that is compiled into an executable, that can be called from the command line. There is a Makefile associated with it.
我正尝试在此处,上面写着
如果要创建然后链接到库,请说 子目录,使用类似
If you want to create and then link to a library, say using code in a subdirectory, use something like
.PHONY: all mylibs
all: $(SHLIB)
$(SHLIB): mylibs
mylibs:
(cd subdir; make)
小心创建所有必要的依赖项,因为没有 保证所有的依赖 将以特定的顺序运行(以及某些CRAN构建机器 使用多个CPU和并行制造商.)
Be careful to create all the necessary dependencies, as there is a no guarantee that the dependencies of all will be run in a particular order (and some of the CRAN build machines use multiple CPUs and parallel makes).
如果我在包中的src
文件夹中创建一个名为someLibrary
的新子目录,代码和Makefile保持不变,然后在我的包的原始Makevars
文件中添加上面的代码保持不变,那么我将能够构建要使用useDynLib
导出的共享库?
If I create a new subdirectory of the src
folder in my package, called someLibrary
, with the code and Makefile unchanged, and in turn, in the original Makevars
file for my package I add the above code unchanged, then I will be able to build that shared library to be exported using useDynLib
?
Following information here, I changed the Makefile
to create a shared library by adding
CFLAG = -fPIC -g -O3
LDFLAGS= -shared
但是,这导致.so
文件没有直接导出到程序包的libs
目录的问题.如果我将路径硬编码到目标中,则文件将发送到程序包的libs
目录(全部通过对R CMD INSTALL myPackage
的调用).
However, this leads to the problem that the .so
file is not exported directly to the libs
directory of the package. If I hard code the path into the target, then the file is sent to the libs
directory of the package (this is all by the way of calls to R CMD INSTALL myPackage
).
最后,我想知道如何调用共享库,因为它具有可以从命令行可执行文件调用的main()
方法.
Lastly, I would like to know how to make calls to the shared library, given that it has a main()
method that I could call from the command line executable.
将其公开给R NAMESPACE
以便可以通过.Call
进行调用的过程是什么?
What is the procedure to expose this to the R NAMESPACE
, so that it can be called via .Call
?
PS.请让我知道是否最后一个问题.
PS. Please let me know if I should make the last bit a separate question.
推荐答案
原始问题的作者在对该问题的评论中要求使用 Automake , Libtool 的示例strong>和LDADD
链接在一个目录中编译的程序与在第二个目录中编译的共享库. 这是一个完整的,独立的,完全有效的示例,说明如何使用GNU Autotools在同一源代码树的单独目录中编译库和程序.
The original question author asked, in the comments on the question, for an example of using Automake, Libtool and LDADD
to link a program compiled in one directory with a shared library compiled in a second directory. This is a complete, standalone, fully worked example of how to compile a library and program in separate directories of the same source tree using GNU Autotools.
我们需要建立一个目录结构,如下所示:
We need to set up a directory structure as follows:
├ A/
│ ├ Makefile.am
│ ├ helloworld.c
│ └ helloworld.h
├ B/
│ ├ Makefile.am
│ └ foo.c
├ configure.ac
└ Makefile.am
共享库将在目录A/
中进行编译,而使用该共享库的程序将在目录B/
中进行编译.
The shared library will be compiled in directory A/
, and the program that uses it in directory B/
.
有三个源文件.
A/helloworld.c
是该库的源代码.它导出一个过程say_hello()
,该过程显示消息"Hello world!".到标准输出.
A/helloworld.c
is the source code of the library. It exports one procedure, say_hello()
, which prints the message "Hello world!" to standard output.
#include <stdio.h>
#include "helloworld.h"
void
say_hello (void)
{
printf ("Hello world!\n");
}
A/helloworld.h
是包含say_hello()
函数声明的头文件.它只有一行:
A/helloworld.h
is the header file that contains the declaration of the say_hello()
function. It only has one line:
void say_hello (void);
最后,B/foo.c
是使用共享库的程序的源代码.它包含库的头文件,并调用say_hello()
.
Finally, B/foo.c
is the source code of the program that uses the shared library. It includes the library's header file, and calls say_hello()
.
#include <helloworld.h>
int
main (int argc, char **argv)
{
say_hello ();
return 0;
}
编译库
我们将使用Automake和Libtool来编译共享库.这两个工具都非常强大,并且实际上有充分的文档记录.手册( Automake ,
Compiling the library
We will use Automake and Libtool to compile the shared library. Both of these tools are very powerful, and actually remarkably well-documented. The manuals (Automake, Libtool) are definitely worth reading.
automake
使用A/Makefile.am
文件来控制库的编译.
The A/Makefile.am
file is used by automake
to control the compilation of the library.
# 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
链接到我们之前编译的库.
Compiling the program
The B/Makefile.am
file controls compilation of the library. We need to use the LDADD
variable to tell automake
to link against the library we compiled earlier.
# 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如何找到所需的工具.
Controlling the build
Finally, we need a top level Makefile.am
to tell Automake how to build the project, and a configure.ac
file to tell Autoconf how to find the required tools.
顶级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
脚本.
Finally, the configure.ac
file tells Autoconf how to create the configure
script.
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!"
You should see the required output: "Hello world!"
这篇关于在子目录中构建共享库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!