Commit | Line | Data |
---|---|---|
156f8ca6 BA |
1 | # Core function to load a package (source R files and compile/load C libraries) |
2 | # @param path Location of the (non-standard) package to be loaded | |
3 | # @param cc Compilator to be used (e.g. 'gcc -std=gnu99' [default]) | |
4 | .pkgdev.load = function(path, cc) { | |
5 | ||
6 | # Get package name from path | |
7 | pathTokens = strsplit(path, c(.Platform$file.sep))[[1]] | |
8 | pkgName = pathTokens[length(pathTokens)] | |
9 | ||
10 | # Create base directory for pkgName under R_HOME_USER/pkgdev/pkgs/pkgName (if not existing) | |
11 | pkdev_path = file.path(Sys.getenv("R_HOME_USER"), "pkgdev") | |
12 | dir.create(file.path(pkdev_path,"pkgs",pkgName), showWarnings=FALSE) | |
13 | ||
14 | # R code first | |
15 | # Warning: R/tests folder should not be sourced | |
16 | forbiddenPath = file.path(path,"R","tests") | |
17 | for (fileOrDir in list.files( file.path(path,"R"),full.names=TRUE )) { | |
18 | if (fileOrDir != forbiddenPath) { | |
19 | if (file.info(fileOrDir)$isdir) { | |
20 | rFiles = list.files(fileOrDir, pattern="\\.[RrSsq]$", | |
672594cf | 21 | full.names=TRUE, recursive=TRUE) |
156f8ca6 BA |
22 | # NOTE: potential unexported functions are not hidden; |
23 | # the developer is assumed to handle this | |
24 | lapply(rFiles, source) | |
25 | } | |
26 | else source(fileOrDir) | |
27 | } | |
28 | } | |
29 | ||
30 | # Also load datasets (if any) | |
31 | rData = list.files(file.path(path,"data"),pattern="\\.R(d|D)ata$",full.names=TRUE) | |
32 | lapply(rData, load) | |
33 | ||
34 | # This file tells if the package is currently loaded | |
35 | pkgLoadFile = file.path(pkdev_path,"pkgs",pkgName,"loaded") | |
672594cf | 36 | |
156f8ca6 BA |
37 | if (file.exists(file.path(path,"src"))) { |
38 | # C code -- Warning: src/tests folder should not be listed | |
d28c1db9 BA |
39 | cFiles = c( |
40 | list.files(file.path(path,"src","sources"),pattern="\\.[cChH]$", | |
41 | full.names=TRUE, recursive=TRUE, no..=TRUE), | |
42 | list.files(file.path(path,"src","adapters"),pattern="\\.[cChH]$", | |
43 | full.names=TRUE, recursive=TRUE, no..=TRUE)) | |
44 | ||
156f8ca6 BA |
45 | # Create folder R_HOME_USER/pkgdev/pkgs/pkgName/src (if not existing) |
46 | dir.create(file.path(pkdev_path,"pkgs",pkgName,"src"), showWarnings=FALSE) | |
47 | ||
48 | # Generate suitable Makefile (all object files go at R_HOME_USER/pkgdev/pkgs/pkgName/src) | |
49 | .generateMakefileLoad(path, cFiles, pkgName, cc) | |
50 | ||
51 | # Compile in the right folder (R_HOME_USER/pkgdev/pkgs/pkgName/src) | |
52 | save_wd = getwd() | |
53 | setwd( file.path(pkdev_path,"pkgs",pkgName,"src") ) | |
54 | library(parallel) | |
55 | system( paste( Sys.getenv("MAKE"), "depend", sep=' ') ) | |
56 | system( paste( Sys.getenv("MAKE"), "-j", detectCores(), "all", sep=' ') ) | |
57 | setwd(save_wd) | |
58 | ||
59 | # Finally load library | |
60 | sharedLib = | |
61 | file.path(pkdev_path,"pkgs",pkgName,paste(pkgName,.Platform$dynlib.ext,sep='')) | |
62 | if (file.exists(pkgLoadFile)) dyn.unload(sharedLib) | |
63 | dyn.load(sharedLib) | |
64 | } | |
65 | ||
66 | # Mark package as 'loaded' | |
672594cf | 67 | file.create(pkgLoadFile) |
156f8ca6 BA |
68 | } |
69 | ||
70 | # Generate appropriate Makefile under R_HOME_USER/pkgdev/pkgs/pkgName/src | |
71 | .generateMakefileLoad = function(path, cFiles, pkgName, cc) { | |
72 | ||
73 | # Preparation: separate cFiles into codes and headers | |
74 | codeFiles = grep(".*(c|C)$", cFiles, value=TRUE) | |
75 | headerFiles = grep(".*(h|H)$", cFiles, value=TRUE) | |
76 | ||
77 | # objectFiles = all .o files in current folder, duplicating file structure under path/src/ | |
78 | basePathFrom = file.path(path, "src") | |
79 | pkdev_path = file.path(Sys.getenv("R_HOME_USER"), "pkgdev") | |
80 | basePathTo = file.path(pkdev_path,"pkgs",pkgName,"src") | |
81 | for (fileOrDir in list.files(basePathFrom, recursive=TRUE, include.dirs=TRUE)) { | |
82 | if (file.info(file.path(basePathFrom,fileOrDir))$isdir) { | |
83 | # Process folders only | |
84 | dir.create(file.path(basePathTo,fileOrDir),showWarnings=FALSE,recursive=TRUE) | |
85 | } | |
86 | } | |
87 | objectFiles = c() | |
88 | for (codeFile in codeFiles) { | |
89 | objectFiles = c( | |
90 | objectFiles, | |
91 | sub("(.*)\\.(c|C)$","\\1\\.o", sub(basePathFrom,basePathTo,codeFile,fixed=TRUE))) | |
92 | } | |
93 | ||
94 | # Build Makefile | |
95 | makefile = paste(' | |
96 | CC = ', cc, ' | |
97 | INCLUDES = -I/usr/include/R/ -I/usr/local/include -I/usr/share/R/include | |
98 | LIBRARIES = -L/usr/lib -L/usr/lib/R/lib -lR -lm | |
99 | CFLAGS = -DNDEBUG -fpic -march=native -mtune=generic -O2 -pipe \\ | |
100 | -fstack-protector --param=ssp-buffer-size=4 -D_FORTIFY_SOURCE=2 | |
101 | LDFLAGS = -shared -Wl,-O1,--sort-common,--as-needed,-z,relro | |
102 | LIB = ', paste(file.path("..",pkgName), .Platform$dynlib.ext, sep=''), ' | |
103 | SRCS = ', paste(codeFiles, sep='', collapse=' '), ' | |
104 | HEDS = ', paste(headerFiles, sep='', collapse=' '), ' | |
105 | OBJS = ', paste(objectFiles, sep='', collapse= ' '), ' | |
106 | all: $(LIB) | |
107 | $(LIB) : $(OBJS) | |
108 | $(CC) $(CFLAGS) $(LDFLAGS) $^ -o $(LIB) $(LIBRARIES)', sep='') | |
109 | compileObjects = "" | |
110 | for (i in 1:length(codeFiles)) { | |
111 | compileObjects = paste(compileObjects, ' | |
112 | ', objectFiles[i], ' : ', codeFiles[i], ' | |
113 | $(CC) $(INCLUDES) $(CFLAGS) -c $< -o $@', sep='') | |
114 | } | |
115 | makefile = paste(makefile, compileObjects, ' | |
116 | .PHONY: clean delib depend | |
117 | clean: | |
118 | rm -f $(OBJS) ./.depend | |
119 | delib: | |
120 | rm -f $(LIB) | |
121 | depend: .depend | |
122 | .depend: $(SRCS) $(HEDS) | |
123 | rm -f ./.depend | |
124 | $(CC) -MM $^ > ./.depend | |
125 | include .depend | |
126 | ', sep='') | |
127 | ||
128 | # Write it to disk | |
129 | writeLines(makefile, file.path(pkdev_path,"pkgs",pkgName,"src","Makefile")) | |
130 | } |