Agent-almanac add-rcpp-integration
git clone https://github.com/pjt222/agent-almanac
T=$(mktemp -d) && git clone --depth=1 https://github.com/pjt222/agent-almanac "$T" && mkdir -p ~/.claude/skills && cp -r "$T/i18n/de/skills/add-rcpp-integration" ~/.claude/skills/pjt222-agent-almanac-add-rcpp-integration-a7d1ff && rm -rf "$T"
i18n/de/skills/add-rcpp-integration/SKILL.mdRcpp-Integration hinzufuegen
C++-Code mit Rcpp fuer leistungskritische Operationen in ein R-Paket integrieren.
Wann verwenden
- R-Funktion ist zu langsam und Profiling bestaetigt einen Engpass
- Schnittstelle zu bestehenden C/C++-Bibliotheken wird benoetigt
- Algorithmen implementieren, die von kompiliertem Code profitieren (Schleifen, Rekursion)
- RcppArmadillo fuer lineare Algebra-Operationen hinzufuegen
Eingaben
- Erforderlich: Bestehendes R-Paket
- Erforderlich: Zu ersetzende oder zu ergaenzende R-Funktion durch C++
- Optional: Externe C++-Bibliothek fuer die Schnittstelle
- Optional: Ob RcppArmadillo verwendet werden soll (Standard: einfaches Rcpp)
Vorgehensweise
Schritt 1: Rcpp-Infrastruktur einrichten
usethis::use_rcpp()
Dies:
- Erstellt
-Verzeichnissrc/ - Fuegt
zu LinkingTo und Imports in DESCRIPTION hinzuRcpp - Erstellt
mitR/packagename-package.R
und@useDynLib@importFrom Rcpp sourceCpp - Aktualisiert
fuer kompilierte Dateien.gitignore
Fuer RcppArmadillo:
usethis::use_rcpp_armadillo()
Erwartet:
src/-Verzeichnis erstellt, DESCRIPTION mit Rcpp in LinkingTo und Imports aktualisiert, und R/packagename-package.R enthaelt @useDynLib-Direktive.
Bei Fehler: Wenn
usethis::use_rcpp() fehlschlaegt, manuell src/ erstellen, LinkingTo: Rcpp und Imports: Rcpp zu DESCRIPTION hinzufuegen und #' @useDynLib packagename, .registration = TRUE sowie #' @importFrom Rcpp sourceCpp zur Paket-Level-Dokumentationsdatei hinzufuegen.
Schritt 2: C++-Funktion schreiben
src/my_function.cpp erstellen:
#include <Rcpp.h> using namespace Rcpp; //' Compute cumulative sum efficiently //' //' @param x A numeric vector //' @return A numeric vector of cumulative sums //' @export // [[Rcpp::export]] NumericVector cumsum_cpp(NumericVector x) { int n = x.size(); NumericVector out(n); out[0] = x[0]; for (int i = 1; i < n; i++) { out[i] = out[i - 1] + x[i]; } return out; }
Fuer RcppArmadillo:
#include <RcppArmadillo.h> // [[Rcpp::depends(RcppArmadillo)]] //' Matrix multiplication using Armadillo //' //' @param A A numeric matrix //' @param B A numeric matrix //' @return The matrix product A * B //' @export // [[Rcpp::export]] arma::mat mat_mult(const arma::mat& A, const arma::mat& B) { return A * B; }
Erwartet: C++-Quelldatei existiert unter
src/my_function.cpp mit gueltiger // [[Rcpp::export]]-Annotation und Roxygen-artigen //'-Dokumentationskommentaren.
Bei Fehler: Pruefen, ob die Datei
#include <Rcpp.h> (oder <RcppArmadillo.h> fuer Armadillo) verwendet, dass die Export-Annotation in einer eigenen Zeile direkt oberhalb der Funktionssignatur steht und die Rueckgabetypen auf gueltige Rcpp-Typen abgebildet sind.
Schritt 3: RcppExports generieren
Rcpp::compileAttributes() devtools::document()
Erwartet:
R/RcppExports.R und src/RcppExports.cpp automatisch generiert.
Bei Fehler: Auf C++-Syntaxfehler pruefen. Sicherstellen, dass das
// [[Rcpp::export]]-Tag oberhalb jeder exportierten Funktion vorhanden ist.
Schritt 4: Kompilierung verifizieren
devtools::load_all()
Erwartet: Paket kompiliert und wird ohne Fehler geladen.
Bei Fehler: Compiler-Ausgabe auf Fehler pruefen. Haeufige Probleme:
- Fehlende System-Header: Entwicklungsbibliotheken installieren
- Syntaxfehler: C++-Compiler-Meldungen zeigen auf die Zeile
- Fehlendes
-Attribut fuer RcppArmadilloRcpp::depends
Schritt 5: Tests fuer kompilierten Code schreiben
test_that("cumsum_cpp matches base R", { x <- c(1, 2, 3, 4, 5) expect_equal(cumsum_cpp(x), cumsum(x)) }) test_that("cumsum_cpp handles edge cases", { expect_equal(cumsum_cpp(numeric(0)), numeric(0)) expect_equal(cumsum_cpp(c(NA_real_, 1)), c(NA_real_, NA_real_)) })
Erwartet: Tests bestehen und bestaetigen, dass die C++-Funktion identische Ergebnisse wie das R-Aequivalent liefert und Grenzfaelle (leere Vektoren, NA-Werte) korrekt behandelt.
Bei Fehler: Wenn Tests bei der NA-Behandlung fehlschlagen, explizite NA-Pruefungen im C++-Code mit
NumericVector::is_na() hinzufuegen. Wenn Tests bei leerer Eingabe fehlschlagen, am Anfang der Funktion eine Schutzklausel fuer Vektoren der Laenge Null hinzufuegen.
Schritt 6: Bereinigungsskript hinzufuegen
src/Makevars erstellen:
PKG_CXXFLAGS = -O2
cleanup im Paketstammverzeichnis erstellen (fuer CRAN):
#!/bin/sh rm -f src/*.o src/*.so src/*.dll
Ausfuehrbar machen:
chmod +x cleanup
Erwartet:
src/Makevars setzt Compiler-Flags und das cleanup-Skript entfernt kompilierte Objekte. Beide Dateien existieren auf Paketstamm-Ebene.
Bei Fehler: Pruefen, ob
cleanup Ausfuehrungs-Berechtigungen hat (chmod +x cleanup) und dass Makevars Tabs (keine Leerzeichen) fuer Einrueckungen verwendet, wenn Makefile-Regeln hinzugefuegt werden.
Schritt 7: .Rbuildignore aktualisieren
Sicherstellen, dass kompilierte Artefakte korrekt behandelt werden:
^src/.*\.o$ ^src/.*\.so$ ^src/.*\.dll$
Erwartet:
.Rbuildignore-Muster verhindern, dass kompilierte Objektdateien in das Paket-Tarball aufgenommen werden, waehrend Quelldateien und Makevars erhalten bleiben.
Bei Fehler:
devtools::check() ausfuehren und nach Hinweisen zu unerwarteten Dateien in src/ suchen. .Rbuildignore-Muster anpassen, um nur .o-, .so- und .dll-Dateien auszuschliessen.
Validierung
-
kompiliert ohne Warnungendevtools::load_all() - Kompilierte Funktion liefert korrekte Ergebnisse
- Tests bestehen fuer Grenzfaelle (NA, leer, grosse Eingaben)
-
besteht ohne KompilierungswarnungenR CMD check - RcppExports-Dateien sind generiert und eingecheckt
- Leistungsverbesserung mit Benchmarks bestaetigt
Haeufige Stolperfallen
vergessen: RcppExports nach Aenderungen an C++-Dateien neu generierencompileAttributes()- Integer-Ueberlauf:
stattdouble
fuer grosse numerische Werte verwendenint - Speicherverwaltung: Rcpp verwaltet Speicher fuer Rcpp-Typen automatisch; nicht manuell
aufrufendelete - NA-Behandlung: C++ kennt Rs NA nicht. Mit
pruefenRcpp::NumericVector::is_na() - Plattformportabilitaet: Plattformspezifische C++-Funktionen vermeiden. Auf Windows, macOS und Linux testen.
- Fehlendes
: Die Paket-Level-Dokumentation muss@useDynLib
enthalten@useDynLib packagename, .registration = TRUE
Verwandte Skills
- Paketeinrichtung vor dem Hinzufuegen von Rcppcreate-r-package
- kompilierte Funktionen testenwrite-testthat-tests
- CI muss C++-Toolchain habensetup-github-actions-ci
- kompilierte Pakete benoetigen zusaetzliche CRAN-Pruefungensubmit-to-cran