Title: | System for Building and Debugging C/C++ Dynamic Libraries |
---|---|
Description: | A build system based on 'GNU make' that creates and maintains (simply) make files in an R session and provides GUI debugging support through 'Microsoft Visual Code'. |
Authors: | Paavo Jumppanen [aut, cre] |
Maintainer: | Paavo Jumppanen <[email protected]> |
License: | GPL-2 |
Version: | 1.1.2 |
Built: | 2024-10-25 06:17:54 UTC |
Source: | https://github.com/pjumppanen/buildsys |
A build system based on 'GNU make' that creates and maintains (simply) make files in an R session and provides GUI debugging support through 'Microsoft Visual Code'.
In the standard R approach dynamic libraries are typically built using the R CMD interface.
That interface in turn uses the GNU make system to build the library through a generic makefile
bundled with R. This is presumably done to simplify the process of building dynamic libraries for
the less experience. The downside however, is adding complexity to the process when doing more esoteric
programming that makes use of static or dynamic libraries outside of those bundled with R. In those
cases it is likely that we may need to specify compiler include options to be able to successfully compile
the code but R CMD SHLIB provides no direct method of acomplishing this task. Instead we have to create a
Makevars file that defines the variables PKG_CFLAGS
, PKG_CXXFLAGS
or PKG_FFLAGS
to achieve the desired outcome.
It is also common to have build issues with libraries not linking because of missing dependencies or link order issues (libraries must be linked in the correct order with gcc to ensure error free linking). Resolving these link related issues is made more complex through the R CMD interface because it is no longer possible to simply look at the makefile definition and make modifications to it in an attempt to resolve the build problem. By having a system approach whereby makefiles are the centre of the build process and not obfuscated away in an R installation folder, the process of debugging build issues is made simpler by virtue of the fact that all necessary changes to fix the build are in one file only, and a simple one at that.
Lastly, a major part of developing library code is debugging and standard R provides little support for that. Developers typically rely on gdb / lldb command line driven debugger support, which is daunting for an inexperienced user, so much so that many will simply resort to print statement based debugging approaches, which whilst capable of resolving bugs, is a cumbersome and slow approach. What is required is an easy to use and full featured GUI based debugger and to that end, Microsoft Visual Code coupled with the machine interface (/MI) support in gdb / lldb provide the perfect solution.
BuildSys
provides a simple but complete and flexible way to create project makefiles, build libraries
and launch GUI based debug sessions, all from within R. The makefiles it creates are permanent rather
than transitory so in the event of build troubles it is easy to resort to tinkering with the makefile
to resolve the cause of the build problem and then reflect the necessary fixes in the R based project
definition.
BuildSys
encapsulates a C/C++ dynamic library project definition into an S4 class BSysProject
.
To create a new project we simply create a new instance of that class and BuildSys
will construct
the appropriate project definition. For example,
Project <- new("BSysProject", "./MyFolder")
will search the directory ./MyFolder
for source files (.c, .cpp
etc) and add them to the project definition.
In searching for source files it will also scan the found source files for include statements and any found includes
will be saved as dependencies for the give source file. No attempt is made to properly parse the source so
if the code uses conditional preprocessing statements the situation may arrise that an include file is
marked as a dependency when for the given build configuration it may not be. In any case, this will not
affect the ability to correctly build the library but will just mean the dependencies are marked wider than true.
Another feature of the dependency check is that any include files not found are considered externalities and
if they belong to a known set, will result in the automatic addition of library and include path dependencies
for the project. Currently BuildSys
knows about TMB.hpp, Rcpp.hpp
and RcppEigen.hpp
, so if any of these are
included into the source file then the necessary include file and define dependencies will be added. This added
feature means TMB and Rcpp users have minimalistic usage requirements to construct libraries with BuildSys
and
need not provide any additional information other than the working folder and possibly the source files being compiled.
A typical project will also need to be given a name but if there is only one source file then the name can be omitted and is inferred from the filename of the source file. For instance, we can explicitly name the project with,
Project <- new("BSysProject", WorkingFolder="./MyFolder", Name="MyProject")
A WorkingFolder
must be provided which names the folder where the source code resides and can be either an absolute path or one
relative to the R working directory.
Finally, if our project is hierarchical in its structure (eg. having source in one folder, header files in another folder,
and binary output in yet another) BuildSys
can accomodate that too. In such case we set Flat=FALSE
with,
Project <- new("BSysProject", WorkingFolder="./MyFolder", Name="MyProject", Flat=FALSE)
For this case the relevent folders are,
MyFolder/src MyFolder/include MyFolder/obj
These sub folder names are the default behaviour. If these sub folder names are not as required they can be renamed
using the SourceName
, IncludeName
and ObjName
arguments in the BSysProject
initilizer.
That is,
Project <- new("BSysProject", WorkingFolder="./MyFolder", Name="MyProject", Flat=FALSE, SourceName="source", IncludeName="header")
Given an existing project, we can also re-initialize it using the initProjectFromFolder
method which has the same
argument list as the initialize
method (it is actually called from the initialize
method). For instance, as with the above,
Project <- initProjectFromFolder(Project, WorkingFolder="./MyFolder", Name="MyProject", Flat=FALSE, SourceName="source", IncludeName="header")
Once we have constructed a Project
object compilation is simply a matter of calling the make
method. As with
traditional GNU makefiles, calling make
with no arguments compiles the dynamic library. Calling make with a
"clean"
argument erases all object files and the built dynamic library. For example,
make(Project) # Compiles the source files and links the dynamic library make(Project, "clean") # deletes all .o object files and the dynamic library
Since the makefile is permanent a subsequent call to make
for an already built project will return immediately
as the library is already present and up to date. If a source file is altered then only the files with stale
dependencies will be recompiled and linked into a new dynamic library build.
Internally make
will call the buildMakefile
method to first construct an up to date makefile representing
the project. Each makefile has an md5 digest in it which will be updated should you alter the project at all and
this stamp is then used to determine if the makefile needs re-construction. If the makefile is re-constructed during
a call to make
then a make clean operation will be carried out to ensure the entire project is re-built. This
should ensure that the state of the project, makefile and the build remains in sync.
Finally, if your project needs to install the library and/or include files to a specific location, that behaviour is also
catered for in BuildSys
. Simply specify the install locations with the InstallLibraryName
and InstallIncludeName
arguments in the BSysProject
initializer. For instance,
Project <- new("BSysProject", WorkingFolder="./MyFolder", Flat=F, InstallLibraryName="inst/lib", InstallIncludeName="inst/include")
Once the project is made using the make
method the dynamic library can be loaded into R memory. We do so using the
loadLibrary
method and we can similarly unload the library using the unloadLibrary
method. The library
name is based upon the project name and the path to the library can be obtained with the libraryPath
method. For example,
loadLibrary(Project) # load the library built by Project unloadLibrary(Project) # unload the library built by Project libraryPath(Project) # return the path to the library built by Project
To debug a dynamic library a debug build must be made to include the symbolic information needed with the dynamic library.
By default, projects constructed using BuildSys
will be created as debug builds. This is controlled by the Debug
argument
supplied in the call to the BSysProject
initilizer. For instance,
Project <- new("BSysProject", Debug=TRUE)
creates a debug enabled project whereas,
Project <- new("BSysProject", Debug=FALSE)
create a release / optimised project. For an existing project we can make a debug build by supplying the Debug
argument
to the call to the make
method as with,
Project <- make(Project, Debug=TRUE)
Recall that for S4 class methods to change the object state we need to assign the returned modified object to the original one,
which is why the above example assigns the make
call to Project
.
Debugging is handled through Microsoft Visual Code and gdb / lldb and it is assumed that these components are installed and functional. For information regarding the installation of these components consult the next section.
To debug an existing dynamic library (built from a BSysProject
) simply call the vcDebug
method as follows.
vcDebug(Project) # Debug the library created by project
Calling this method will open an instance of Microsoft Visual Code that is correctly initialised to debug your library code. Within
Visual Code you can open the source file/s of your library, set breakpoints and run a debug session. To run a debug
session select the run/Start Debugging menu item. Doing so will result in a new instance of R being launched which contains
the same environment (including loaded packages and loaded dynamic libraries) as the parent R session where vcDebug
was first
called. This R session is your sandbox to safely debug your library in and leaves the parent R session safe from loss should
your code crash R completely.
Typically when debugging a new library the library requires R setup code to initialise as a foundation for library use and/or testing.
With BuildSys
you should perform this initial setup of R in the parent R session before calling vcDebug
so that you
never have to initialise R in your debug session. Its correct state will have been initialised from the parent R session.
In order to debug code with BuildSys
Microsoft Visual Code must be installed. You can download and install this software from
here:
Choose the appropriate installer for your operating system. On Windows and Linux the installer should include code in the PATH
environment variable.
Verify this by opening a new shell/command prompt and typing,
code
and enter. If Visual Code starts then the PATH
enviroment variable is correctly set. If it fails to start then add it to the
system PATH
environment variable.
On MacOS the application name is Visual Studio Code.app
and is an application bundle. For it to be usable by BuildSys drag the Visual Studio Code application bundle to the Applications folder using Finder.
On Windows you will have to install Rtools which you can find here:
You will need to add R and Rtools to the system Path. For instance add,
C:\rtools40\mingw64\bin\ C:\rtools40\usr\bin\ C:\Program Files\R\R-4.0.1\bin\x64\
but be aware that the locations may differ in your case depending on which version of R and Rtools and where these products were installed. To set environment variables in Windows 10,
Open the Start Search, type in “env”, and choose “Edit the system environment variables”:
Click the “Environment Variables...” button.
Set the environment variables as needed. The New button adds an additional variable.
Dismiss all of the dialogs by choosing “OK”. Your changes are saved!
In Windows after installing Rtools we also need to install gdb. To install gdb, open an MSYS2 shell (In explorer migrate to the Rtools40 folder and double click on msys2.exe) and enter the following commands,
pacman -Sy pacman -S mingw-w64-{i686,x86_64}-gdb
After installing verify that gdb is installed by opening a new DOS box and typing,
gdb -v
If all is correct it should respond with something like,
GNU gdb (GDB) 8.3.1 Copyright (C) 2019 Free Software Foundation, Inc. License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> This is free software: you are free to change and redistribute it. There is NO WARRANTY, to the extent permitted by law.
On MacOS / OS X you will need to install Xcode to have access to both clang and lldb. Go to Mac App Store and download and install Xcode.
On Linux you will need to have gcc installed. Installation of gcc on Linux is omitted because of the many and varied ways to do so depending on the distribution being used. Please consult Google on this topic for more information on installing development tools on Linux.
On Windows and Linux, you will also need to install the Microsoft C/C++ IntelliSense, debugging, and code browsing extension in Microsoft Visual Code. To install, press Ctrl+Shift+X and search for C/C++ and then click on Install beside the Microsoft C/C++ IntelliSense, debugging, and code browsing entry in the list. On MacOS / OS X you will need to install the Microsoft C/C++ IntelliSense, debugging, and code browsing and CodeLLDB extensions. To install press CMD+Shift+X and search for C/C++ and then click on Install beside the Microsoft C/C++ IntelliSense, debugging, and code browsing entry in the list, then also search for CodeLLDB and click on the Install next to Native debugger based on LLDB in the list.
On MacOS (OS X 10.11 and later) Apple introduced System Integrity Protection which restricts the ability to debug your code from within an R session. To debug code in R using BuildSys and CodeLLDB will require that the debugging restrictions are disabled. To do so shutdown MacOS, then press and hold down CMD+R keys while pressing the power button and keep them depressed until you see a language selection dialog. After selecting the language you should see the Utilities Window. In the menu bar at the top of the screen select the utilities/Terminal menu and in the terminal session enter the follow command:
csrutil enable --without debug
You will be prompted for your password. Enter your password to carry out the command. If successful you will be presented with a warning about it being a non-standard configuration. Now re-boot your Mac by selecting the re-boot option from the Apple menu at the top of the screen. You should now be able to debug your R dynamic libraries with BuildSys.
If the absolute path to source and dynamic library files contains spaces then debugging in Visual Code fails to function correctly. To ensure code is debuggable users will need to avoid putting code in folders with whitespace in the folder names.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
Debug C++ in Visual Studio Code
Disabling and Enabling System Integrity Protection
Enabling parts of System Integrity Protection while disabling specific parts?
make
buildMakefile
vcDebug
loadLibrary
unloadLibrary
libraryPath
sourcePath
includePath
objPath
installLibraryPath
installIncludePath
clean
ProjectFolder <- tempdir() # Create source file for finite convolution example in "Writing R Extensions" lines <- c( "#include <R.h>", "#include <Rinternals.h>", "", "SEXP convolve2(SEXP a, SEXP b)", "{", " int na, nb, nab;", " double *xa, *xb, *xab;", " SEXP ab;", "", " a = PROTECT(coerceVector(a, REALSXP));", " b = PROTECT(coerceVector(b, REALSXP));", " na = length(a); nb = length(b); nab = na + nb - 1;", " ab = PROTECT(allocVector(REALSXP, nab));", " xa = REAL(a); xb = REAL(b); xab = REAL(ab);", " for(int i = 0; i < nab; i++) xab[i] = 0.0;", " for(int i = 0; i < na; i++)", " for(int j = 0; j < nb; j++) xab[i + j] += xa[i] * xb[j];", " UNPROTECT(3);", " return ab;", "}") SourceFilePath <- paste0(ProjectFolder, "/convolve.c") writeLines(lines, SourceFilePath) # digest need not be loaded but the digest package needs to be installed # as it is used to create a digest of the project to track the need for # makefile re-creation. require(BuildSys) # create project to build shared library, a flat project with source in current working directory. Project <- new("BSysProject", ProjectFolder) # re-initialise project from current working directory, new("BSysProject") calls this internally Project <- initProjectFromFolder(Project, ProjectFolder) # build the shared library make(Project) # get project library path libraryPath(Project) # get project source path sourcePath(Project) # get project include path includePath(Project) # get project object path objPath(Project) # get project install library path installLibraryPath(Project) # get project install include path installIncludePath(Project) # load the library loadLibrary(Project) # R wrapper on .Call conv <- function(a, b) .Call("convolve2", a, b) # Test data a <- rnorm(100) b <- rep(1.0, times=10) # call the shared library function conv(a, b) ## Not run: # open a debug session - assumes Visual Studio Code is installed as directed in the # package documentation. This will open a Visual Studio Code session. In that session # open the convolve.c source file and set breakpoints, then select the "run/start debugging" # menu to debug. This will start a new R session with the same state as the parent # R session where vcDebug() is first called. In the new debug session run the following # command: # # conv(a, b) vcDebug(Project) ## End(Not run) # unload the shared library unloadLibrary(Project) # clean up example make(Project, "clean") clean(Project) unlink(SourceFilePath)
ProjectFolder <- tempdir() # Create source file for finite convolution example in "Writing R Extensions" lines <- c( "#include <R.h>", "#include <Rinternals.h>", "", "SEXP convolve2(SEXP a, SEXP b)", "{", " int na, nb, nab;", " double *xa, *xb, *xab;", " SEXP ab;", "", " a = PROTECT(coerceVector(a, REALSXP));", " b = PROTECT(coerceVector(b, REALSXP));", " na = length(a); nb = length(b); nab = na + nb - 1;", " ab = PROTECT(allocVector(REALSXP, nab));", " xa = REAL(a); xb = REAL(b); xab = REAL(ab);", " for(int i = 0; i < nab; i++) xab[i] = 0.0;", " for(int i = 0; i < na; i++)", " for(int j = 0; j < nb; j++) xab[i + j] += xa[i] * xb[j];", " UNPROTECT(3);", " return ab;", "}") SourceFilePath <- paste0(ProjectFolder, "/convolve.c") writeLines(lines, SourceFilePath) # digest need not be loaded but the digest package needs to be installed # as it is used to create a digest of the project to track the need for # makefile re-creation. require(BuildSys) # create project to build shared library, a flat project with source in current working directory. Project <- new("BSysProject", ProjectFolder) # re-initialise project from current working directory, new("BSysProject") calls this internally Project <- initProjectFromFolder(Project, ProjectFolder) # build the shared library make(Project) # get project library path libraryPath(Project) # get project source path sourcePath(Project) # get project include path includePath(Project) # get project object path objPath(Project) # get project install library path installLibraryPath(Project) # get project install include path installIncludePath(Project) # load the library loadLibrary(Project) # R wrapper on .Call conv <- function(a, b) .Call("convolve2", a, b) # Test data a <- rnorm(100) b <- rep(1.0, times=10) # call the shared library function conv(a, b) ## Not run: # open a debug session - assumes Visual Studio Code is installed as directed in the # package documentation. This will open a Visual Studio Code session. In that session # open the convolve.c source file and set breakpoints, then select the "run/start debugging" # menu to debug. This will start a new R session with the same state as the parent # R session where vcDebug() is first called. In the new debug session run the following # command: # # conv(a, b) vcDebug(Project) ## End(Not run) # unload the shared library unloadLibrary(Project) # clean up example make(Project, "clean") clean(Project) unlink(SourceFilePath)
"BSysProject"
BSysProject
implements a build system based on GNU make that creates and
maintains (simply) makefiles in an R session and provides GUI debugging support
through Microsoft Visual Code.
Objects can be created by calls of the form:
new("BSysProject", WorkingFolder, Name, SourceFiles, SourceName, IncludeName, ObjName, InstallLibraryName, InstallIncludeName, Flat, Packages, Includes, Defines, Libraries, CFLAGS, CXXFLAGS, FFLAGS, LDFLAGS, LDLIBS, DEFINES, Debug)
For more information consult initProjectFromFolder
.
WorkingFolder
:Object of class "character"
that is the absolute path to the root folder of the project.
ProjectName
:Object of class "character"
that is the name given to the project and will form the basename of the shared library.
SourceName
:Object of class "character"
that is the sub-path / sub-drectory of the source folder (containing .c
, .cpp
files)
in the project.
IncludeName
:Object of class "character"
that is the sub-path / sub-drectory of the include folder (containing .h
, .hpp
files)
in the project.
ObjName
:Object of class "character"
that is he sub-path / sub-drectory of the object folder (containing the compiled .o
files) in the project.
InstallLibraryName
:Object of class "character"
that is the sub-path / sub-drectory of the folder to install the compiled shared library to.
InstallIncludeName
:Object of class "character"
that is the sub-path / sub-drectory of the folder to install the shared library header files to.
Flat
:Object of class "logical"
that determines if the project is assumed flat or heirarchical. If flat
then all the source and include files are assumed to reside in the WorkingFolder
, otherwise they
are assumed to be in the sub-folders descibed by the SourceName
, IncludeName
and ObjName
arguments.
SourceFiles
:Object of class "list"
is a "BSysSourceFile" list
that names the source files of the project.
Packages
:Object of class "character"
is a string list
that names the packages that this library is depenedent
on (C/C++ include dependencies).
Includes
:Object of class "character"
is a string list
that contains the include paths of external dependencies
of the library code.
Defines
:Object of class "character"
is a string list
that contains preprocessor (#defines) defines
required to compile the code.
Libraries
:Object of class "character"
is a string list
that names the additional library dependencies needed
to link the library. The format is as required by gcc. For instance, "-L/usr/local/lib -lexpat"
would
constitute a single item in the list.
CFLAGS
:Object of class "character"
is a string list
naming additional gcc flags to apply when
compiling .c
files.
CXXFLAGS
:Object of class "character"
is a string list
naming additional gcc flags to apply when
compiling .cpp
files.
FFLAGS
:Object of class "character"
is a string list
naming additional gcc flags to apply when
compiling .f
files.
LDFLAGS
:Object of class "character"
is a string list
naming additional gcc flags to apply when
linking .o
files.
LDLIBS
:Object of class "character"
is a string list
naming additional gcc linker flags to apply
when linking .o
files.
DEFINES
:Object of class "character"
is a string list
that contains preprocessor (#defines) defines
supplied when compiling the code.
IsDebug
:Object of class "logical"
is a Boolean
that indicates whether to create a debug build.
DebugState
:Object of class "list"
used internally to manage debugging.
signature(.Object = "BSysProject")
: see buildMakefile
signature(.Object = "BSysProject")
: see includePath
signature(.Object = "BSysProject")
: see initProjectFromFolder
signature(.Object = "BSysProject")
: see installIncludePath
signature(.Object = "BSysProject")
: see installLibraryPath
signature(.Object = "BSysProject")
: see libraryPath
signature(.Object = "BSysProject")
: see loadLibrary
signature(.Object = "BSysProject")
: see make
signature(.Object = "BSysProject")
: see objPath
signature(.Object = "BSysProject")
: sourcePath
signature(.Object = "BSysProject")
: unloadLibrary
signature(.Object = "BSysProject")
: vcDebug
signature(.Object = "BSysProject")
: clean
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
"BSysSourceFile"
This class is for internal use only and is used to track the source files and
corresponding dependecies that make up a BSysProject
.
Objects can be created by calls of the form new("BSysSourceFile", Filename, SrcFolder, IncludeFolder, Type)
. Users
should not be using this class directly. Instances of this class are used to track the source files and
corresponding dependecies that make up a BSysProject
.
Filename
:Object of class "character"
is the file name and path of a file in a BSysProject
object instance.
Type
:Object of class "character"
is a string naming the source file type ("c"
, "cpp"
or "f"
).
Dependencies
:Object of class "list"
is a list of fully qualified include file dependencies for this source file.
Externals
:Object of class "list"
is a list of external include file dependencies (the file is not in the includePath
.
No methods defined with class "BSysSourceFile" in the signature.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
Calling buildMakefile
builds a GNU makefile based on the project specification in the S4 BSysProject
object instance.
## S4 method for signature 'BSysProject' buildMakefile(.Object, Force = FALSE)
## S4 method for signature 'BSysProject' buildMakefile(.Object, Force = FALSE)
.Object |
|
Force |
|
buildMakefile
constructs a makefile that represents the project specfication in the S4 BSysProject
object instance.
That instance is created with a call to new("BSysProject", ...)
constructor (see initProjectFromFolder
). If the makefile
already exists and is in sync with Object
then the makefile is left untouched, unless Force=TRUE
, in which case it is written afresh.
A makefile is determined to be in sync with the parent project by comparison of an md5 digest of the BSysProject
object instance
and the digest stored in the header comment line of the makefile.
Returns TRUE
if the makefile is created or re-created and FALSE
otherwise.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
make
initProjectFromFolder
BuildSys-package
Calling clean
will remove the files and folders created by the
project.
## S4 method for signature 'BSysProject' clean(.Object)
## S4 method for signature 'BSysProject' clean(.Object)
.Object |
|
this method has no return value.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
Calling includePath
will return the fully qualified path to the include
file folder of the project specification in the S4 BSysProject
object instance.
## S4 method for signature 'BSysProject' includePath(.Object)
## S4 method for signature 'BSysProject' includePath(.Object)
.Object |
|
returns the fully qualified path to the include file folder of the project.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
libraryPath
sourcePath
objPath
installLibraryPath
installIncludePath
BSysProject
Instance based on a Project Folder
Calling initProjectFromFolder
initialises a project specification in an S4 BSysProject
object instance. That
object instance can then be used to compile and debug the resulting shared library. A new BSysProject
object instance
can be constructed by calling new("BSysProject", ...)
where the argument list (...) is the same as for initProjectFromFolder
.
## S4 method for signature 'BSysProject' initProjectFromFolder(.Object, WorkingFolder = "NULL", Name = "", SourceFiles = "NULL", SourceName = "src", IncludeName = "include", ObjName = "obj", InstallLibraryName = as.character(NULL), InstallIncludeName = as.character(NULL), Flat = TRUE, Packages = as.character(c()), Includes = as.character(c()), Defines = as.character(c()), Libraries = as.character(c()), CFLAGS = as.character(c()), CXXFLAGS = as.character(c()), FFLAGS = as.character(c()), LDFLAGS = as.character(c()), LDLIBS = as.character(c()), DEFINES = as.character(c()), Debug = TRUE)
## S4 method for signature 'BSysProject' initProjectFromFolder(.Object, WorkingFolder = "NULL", Name = "", SourceFiles = "NULL", SourceName = "src", IncludeName = "include", ObjName = "obj", InstallLibraryName = as.character(NULL), InstallIncludeName = as.character(NULL), Flat = TRUE, Packages = as.character(c()), Includes = as.character(c()), Defines = as.character(c()), Libraries = as.character(c()), CFLAGS = as.character(c()), CXXFLAGS = as.character(c()), FFLAGS = as.character(c()), LDFLAGS = as.character(c()), LDLIBS = as.character(c()), DEFINES = as.character(c()), Debug = TRUE)
.Object |
|
WorkingFolder |
The path to the root folder of the project, either relative or absolute and must be supplied. |
Name |
The name given to the project and will form the basename of the shared library. |
SourceFiles |
The a list of file names in WorkingFolder that should be compiled as part of the project or |
SourceName |
The sub-path / sub-drectory of the source folder (containing |
IncludeName |
The sub-path / sub-drectory of the include folder (containing |
ObjName |
The sub-path / sub-drectory of the object folder (containing the compiled |
InstallLibraryName |
The sub-path / sub-drectory of the folder to install the compiled shared library to. |
InstallIncludeName |
The sub-path / sub-drectory of the folder to install the shared library header files to. |
Flat |
A |
Packages |
A |
Includes |
A |
Defines |
A |
Libraries |
A |
CFLAGS |
A |
CXXFLAGS |
A |
FFLAGS |
A |
LDFLAGS |
A |
LDLIBS |
A |
DEFINES |
A |
Debug |
A |
initProjectFromFolder
constructs a project specification by scanning the WorkingFolder
and relevant sourceName
sub path for source files to add to the project. If the SourceFiles
is included the the source file scan is omitted and only the named source files included. The named files
are assumed relative to the Working Folder so if a hierarchical project is being created then the relative
path to the source folder will need to be included in the SourceFiles
list. Any .c
, .cpp
and .f
files it finds are added to the project. In the case of Fortran files the following extensions
are scanned; .f
, .for
, .f90
, .f95
and .f77
. Any added files are scanned
for include directives and those includes are added as project dependencies. If the dependency is not found
in the path described by the includeName
it is regarded as an external dependency.
If the external dependency is known (TMB.hpp
for example) then the appropriate Includes
,
Defines
and Libraries
are added to the project definition. BuildSys
is currently
aware of TMB
, Rcpp
, RcppEigen
and the BLAS
library support in R. External
dependencies not know to BuildSys
need to be handle by adding the appropriate Includes
,
Defines
and Libraries
to the Project manually with the arguments provided above.
initProjectFromFolder
has useful defaults meaning in most cases very few arguments need be provided.
At most, the WorkingFolder
and Name
arguments will be required but if the project has only
a single source file then even Name
can be omitted as the name will be inferred from the source file name.
returns an S4 object instance of class BSysProject
that describes the code project.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
make
buildMakefile
vcDebug
loadLibrary
unloadLibrary
libraryPath
sourcePath
includePath
objPath
installLibraryPath
installIncludePath
BuildSys-package
Calling installIncludePath
will return the fully qualified path to the install include
file folder of the project specification in the S4 BSysProject
object instance.
This is the folder where the shared library include files will be copied to when calling
make(Project, "install")
.
## S4 method for signature 'BSysProject' installIncludePath(.Object)
## S4 method for signature 'BSysProject' installIncludePath(.Object)
.Object |
|
returns the fully qualified path to the install include file folder of the project specification.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
libraryPath
sourcePath
includePath
objPath
installLibraryPath
Calling installLibraryPath
will return the fully qualified path to the install library
file folder of the project specification in the S4 BSysProject
object instance.
This is the folder where the shared library will be copied to when calling make(Project, "install")
.
## S4 method for signature 'BSysProject' installLibraryPath(.Object)
## S4 method for signature 'BSysProject' installLibraryPath(.Object)
.Object |
|
returns the fully qualified path to the install library file folder of the project specification.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
libraryPath
sourcePath
includePath
objPath
installIncludePath
Calling libraryPath
will return the fully qualified path to the built
shared library of the project specification in the S4 BSysProject
object instance.
## S4 method for signature 'BSysProject' libraryPath(.Object)
## S4 method for signature 'BSysProject' libraryPath(.Object)
.Object |
|
returns the fully qualified path to the built shared library of the project specification.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
sourcePath
includePath
objPath
installLibraryPath
installIncludePath
Calling loadLibrary
will load the built library of the project specification in the S4 BSysProject
object instance
into the R session.
## S4 method for signature 'BSysProject' loadLibrary(.Object)
## S4 method for signature 'BSysProject' loadLibrary(.Object)
.Object |
|
Internally this method delagates to dyn.load
. Refer to the doucmentation of dyn.load
for further details.
returns an object of class DLLInfo
.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
Calling make
will build, clean or install your C/C++ library.
## S4 method for signature 'BSysProject' make(.Object, Operation = "", Debug = NULL)
## S4 method for signature 'BSysProject' make(.Object, Operation = "", Debug = NULL)
.Object |
S4 |
Operation |
the
|
Debug |
A |
Calling make
results in the project described by the Object
instance being transformed into a GNU makefile and then
GNU make being called with the appropriate operation as determined by the Operation
argument. The makefile will be
written to the sub-folder specified by the ObjName
attribute of the Object
instance. If the makefile already exists it
will only be re-created if the existing one in not in sync with the project definition. This is determined by an md5 digest of
the project definition which is stored as the header comment line in the makefile. If the makefile is re-written then a make clean
operation will be automatically carried out to ensure the built library remains in sync with the makefile.
This method returns an updated S4 BSysProject
object instance. If the any change to Debug
state is to be preserved then the
returned result should be assigned to the calling BSysProject
object instance passed in the Object
argument.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
buildMakefile
initProjectFromFolder
BuildSys-package
Calling objPath
will return the fully qualified path to the object
file folder of the project specification in the S4 BSysProject
object instance.
The object file folder will contain the makefile and compiled (object) .o
files as
well as the linked shared library.
## S4 method for signature 'BSysProject' objPath(.Object)
## S4 method for signature 'BSysProject' objPath(.Object)
.Object |
|
returns the fully qualified path to the object file folder of the project specification.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
libraryPath
sourcePath
includePath
installLibraryPath
installIncludePath
Calling sourcePath
will return the fully qualified path to the source
file folder of the project specification in the S4 BSysProject
object instance.
## S4 method for signature 'BSysProject' sourcePath(.Object)
## S4 method for signature 'BSysProject' sourcePath(.Object)
.Object |
|
returns the fully qualified path to the source file folder of the project specification.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
libraryPath
includePath
objPath
installLibraryPath
installIncludePath
Calling unloadLibrary
will unload the built library of the project specification in the S4 BSysProject
object instance
from the R session.
## S4 method for signature 'BSysProject' unloadLibrary(.Object)
## S4 method for signature 'BSysProject' unloadLibrary(.Object)
.Object |
|
Internally this method delagates to dyn.unload
. Refer to the doucmentation of dyn.unload
for further details.
this method has no return value.
see BuildSys-package
for examples of use.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
Calling vcDebug
will initiate a debug enabled Microsoft Visual Code instance
that can be use as a GUI debugger of your C/C++ code.
## S4 method for signature 'BSysProject' vcDebug(.Object, LaunchEditor=TRUE)
## S4 method for signature 'BSysProject' vcDebug(.Object, LaunchEditor=TRUE)
.Object |
|
LaunchEditor |
|
vcDebug
creates the necessary c_cpp_properties.json
and launch.json
files needed for Microsoft Visual Code
to effectively debug the project dynamic library and launches an instance of Visual Code. It is assumed that the dynamic
library has already been compiled with make
and Debug
support enabled. R needs to be configured to be able to build
C/C++ libraries (RTools installed on Windows) and it is assumed that Microsoft Visual Code is installed. These requirements
are discussed at length in BuildSys-package
.
Within Visual Code you can open the source file/s of your library, set breakpoints and run a debug session. To run a debug
session select the run/Start Debugging menu item. Doing so will result in a new instance of R being launched which contains
the same environment (including loaded packages and loaded dynamic libraries) as the parent R session where vcDebug
was first
called. This R session is your sandbox to safely debug your library in and leaves the parent R session safe from loss should
your code crash R completely.
Debugging a new library will typically require some R setup code to be executed before using and/or testing it. With BuildSys
you
should perform this initial setup of R in the parent R session before calling vcDebug
so that you never have to initialise
R in your debug session. The debug R session will inherit the state of the parent R session at the time that vcDebug
was called.
this method returns no value.
see BuildSys-package
for examples of use.
If the absolute path to source and dynamic library files contains spaces then debugging in Visual Code fails to function correctly. To ensure code is debuggable users will need to avoid putting code in folders with whitespace in the folder names.
Paavo Jumppanen [aut, cre]
Maintainer: Paavo Jumppanen <[email protected]>
initProjectFromFolder
make
BuildSys-package