How can I load C++ modules and include compilation flags as a part of Rcpp package compilation?

395 views Asked by At

I am using Rcpp to wrap a C++ program in an R package. My C++ program requires the following header:

#include "htslib/sam.h"

Prior to compilation, I typically load the following module in Ubuntu:

HTSlib/1.11-GCC-9.3.0

I typically compile the C++ script with the following flags in Ubuntu using GCC/9.3.0:

g++ scriptname.cpp -Ihtslib -Lhtslib -lhts

Since I am accessing the program from R via Rcpp, I do not know how to load the HTSlib module. When I attempt to "Clean and Rebuild" the package, I get the following error:

fatal error: htslib/sam.h: No such file or directory
    #include "htslib/sam.h"
                           ^
   compilation terminated.

I have two questions:

  1. How do I load C++ modules when building an R package from C++ source code?

  2. How do I include compilation flags when building an R package from C++ source code?

I have created a minimal header file, .R file, and C++ source script. The script opens a bam file and outputs the chromosome names and positions of the reads. These files do not represent the actual program I want to run (which is much too long and complicated to include here), but generate the same error when I attempt to build a package using Rcpp.

C++ source file:

#include "htslib/sam.h"
#include <string>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <Rcpp.h>
#include "HTSlibBasics.h

void OpenBam(std::string command_string){
    // Stores filename and converts to character string
    const char * char_command;
    char_command = command_string.c_str();
    
    // Opens bam file
    samFile *fp = sam_open(char_command, "r");
    
    // Opens bam header
    bam_hdr_t *h = sam_hdr_read(fp);
    
    // Initialize an alignment
    bam1_t *b = bam_init1();
    
    while(sam_read1(fp, h, b) >= 0) {
        if (b->core.tid < 0){
            continue;
        }else{
            std::cout << h->target_name[b->core.tid] << "\t" << b->core.pos << "\t" << bam_endpos(b) << std::endl;
       }
    }
    
    /*
    * Destroy the alignment and header which have been read into the C++ program
    * and close the sam file.
    */
    bam_destroy1(b);
    bam_hdr_destroy(h);
    sam_close(fp);
}

Header file:

#ifndef OPEN_BAM
#define OPEN_BAM

//' Documentation
//' @param command_string Documentation
// [[Rcpp::export]]
void OpenBam(std::string command_string);

#endif // OPEN_BAM

R file:

## usethis namespace: start
#' @useDynLib HTSlibBasics, .registration = TRUE
## usethis namespace: end
NULL
## usethis namespace: start
#' @importFrom Rcpp sourceCpp
## usethis namespace: end
NULL
#' Documentation
#' @export
OpenBam <- function(command_string) {
  .Call(`_HTSlibBasics_OpenBam`, command_string)
}

The R file goes in the "R" directory of the package while the C++ script and header go in the "src" directory.

1

There are 1 answers

3
annabelperry On

I figured it out: turns out the answer was pretty simple. I loosely followed Dirk Eddelbuettel's vignette (https://cloud.r-project.org/web/packages/Rcpp/vignettes/Rcpp-libraries.pdf) and also combined a whole bunch of info from across the web.

In the command-line, I navigated to the HTSlib directory on my system:

cd /sw/eb/sw/HTSlib/1.11-GCC-9.3.0/

Next, I navigated to the directory with the htslib header files and moved them to the src/ directory for my R package:

cd include/htslib
cp *.h /home/annabelperry/R/HTSlibBasics/src/

Then, I navigated to my C++ source file and changed the header include "htslib/sam.h" to include "sam.h", as my sam.h file was no longer in the htslib directory.

I then navigated to the HTSlib libraries directory and copied each of the files to a directory just outside my R package. (Note: I tried copying the whole directory and moving it, but this led to edit access issues).

cd /sw/eb/sw/HTSlib/1.11-GCC-9.3.0/lib
cp libhts.a /home/annabelperry/R/lib/
cp libhts.so /home/annabelperry/R/lib/
cp libhts.so.1.11 /home/annabelperry/R/lib/
cp libhts.so.3 /home/annabelperry/R/lib/
cd pkgconfig
cp htslib.pc /home/annabelperry/R/lib/pkgconfig/

I then created a file titled Makevars in the src/ directory for my R package and entered this:

CXX_STD = CXX11
PKG_CXXFLAGS = -Ihtslib
PKG_LIBS = -L/home/annabelperry/R/lib -lhts -Wl,-rpath,/home/annabelperry/R/lib

The -L linker flag gives the directory in which to find the library files and the -l linker flag gives the base name of the library files.

When I tried to build the package, I got an error saying the libcrypto.so.10 library could not be found. I moved this library from its original directory, /usr/lib64, to the /home/annabelperry/R/lib/ directory with the rest of my library files.

I also had to remove all std::cout calls from my source code, as they are incompatible with Rcpp.

After this, I could successfully build the package.