@@ -5,7 +5,12 @@ import java.io.File
5
5
import java .nio .file .{Files , Path }
6
6
import java .util .Arrays
7
7
import java .util .regex ._
8
+
8
9
import scala .concurrent ._
10
+ import scala .util .Failure
11
+ import scala .util .Success
12
+
13
+ import scalanative .build .IO .RichPath
9
14
import scala .scalanative .linker .ReachabilityAnalysis
10
15
11
16
/** Original jar or dir path and generated dir path for native code */
@@ -14,16 +19,18 @@ private[scalanative] case class NativeLib(src: Path, dest: Path)
14
19
/** Utilities for dealing with native library code */
15
20
private [scalanative] object NativeLib {
16
21
17
- /** Name of directory that contains native code: "scala-native"
18
- */
22
+ /** Name of directory that contains native code: "scala-native" */
19
23
val nativeCodeDir = " scala-native"
20
24
25
+ /** Project Descriptor properties file: "scala-native.properties" */
26
+ private val nativeProjectProps = s " ${nativeCodeDir}.properties "
27
+
21
28
/** Compiles the native code from the library
22
29
*
23
30
* @param config
24
31
* the configuration options
25
32
* @param linkerResult
26
- * needed for filtering
33
+ * needed for configuration based on NIR
27
34
* @param nativeLib
28
35
* the native lib to unpack
29
36
* @return
@@ -34,11 +41,105 @@ private[scalanative] object NativeLib {
34
41
analysis : ReachabilityAnalysis .Result ,
35
42
nativeLib : NativeLib
36
43
)(implicit ec : ExecutionContext ): Future [Seq [Path ]] = {
37
- val destPath = NativeLib .unpackNativeCode(nativeLib)
38
- val paths = NativeLib .findNativePaths(config.workDir, destPath)
39
- val (projPaths, projConfig) =
40
- Filter .filterNativelib(config, analysis, destPath, paths)
41
- LLVM .compile(projConfig, projPaths)
44
+ val destPath = unpackNativeCode(nativeLib)
45
+ val paths = findNativePaths(config.workDir, destPath)
46
+ val projConfig = configureNativelib(config, analysis, destPath)
47
+ LLVM .compile(projConfig, paths)
48
+ }
49
+
50
+ /** Update the project configuration the if a project `Descriptor` is present.
51
+ *
52
+ * @param config
53
+ * The configuration of the toolchain.
54
+ * @param linkerResult
55
+ * The results from the linker.
56
+ * @param destPath
57
+ * The unpacked location of the Scala Native nativelib.
58
+ * @return
59
+ * The config for this native library.
60
+ */
61
+ private def configureNativelib (
62
+ config : Config ,
63
+ analysis : ReachabilityAnalysis .Result ,
64
+ destPath : Path
65
+ ): Config = {
66
+ val nativeCodePath = destPath.resolve(nativeCodeDir)
67
+ // check if filtering is needed, o.w. return all paths
68
+ findDescriptor(nativeCodePath).fold(config) { filepath =>
69
+
70
+ val desc =
71
+ Descriptor .load(filepath) match {
72
+ case Success (v) => v
73
+ case Failure (e) =>
74
+ throw new BuildException (
75
+ s " Problem reading $nativeProjectProps: ${e.getMessage}"
76
+ )
77
+ }
78
+
79
+ config.logger.debug(desc.toString())
80
+
81
+ val projectConfig = desc match {
82
+ case Descriptor (Some (groupId), Some (artifactId), _)
83
+ if (groupId == " org.scala-native" && artifactId == " nativelib" ) =>
84
+ createGcConfig(nativeCodePath, config)
85
+ case Descriptor (_, _, _) =>
86
+ createLinkConfig(desc, analysis, config)
87
+ }
88
+
89
+ projectConfig
90
+ }
91
+ }
92
+
93
+ private def createLinkConfig (
94
+ desc : Descriptor ,
95
+ analysis : ReachabilityAnalysis .Result ,
96
+ config : Config
97
+ ): Config = {
98
+ val linkDefines =
99
+ desc.link
100
+ .filter(name => analysis.links.exists(_.name == name))
101
+ .map(name => s " -DSCALANATIVE_LINK_ ${name.toUpperCase}" )
102
+
103
+ config.withCompilerConfig(
104
+ _.withCompileOptions(_ ++ linkDefines)
105
+ )
106
+ }
107
+
108
+ private def createGcConfig (
109
+ nativeCodePath : Path ,
110
+ config : Config
111
+ ): Config = {
112
+ /* A conditional compilation define is used to compile the
113
+ * correct garbage collector code because code is shared.
114
+ * This avoids handling all the paths needed and compiling
115
+ * all the GC code for a given platform.
116
+ *
117
+ * Note: The zone directory is also part of the garbage collection
118
+ * system and shares code from the gc directory.
119
+ */
120
+ val gcFlag = {
121
+ val gc = config.compilerConfig.gc.toString
122
+ s " -DSCALANATIVE_GC_ ${gc.toUpperCase}"
123
+ }
124
+
125
+ val gcPath = nativeCodePath.resolve(" gc" ).abs
126
+
127
+ config.withCompilerConfig(
128
+ _.withCompileOptions(_ :+ (" -I" + gcPath) :+ gcFlag)
129
+ )
130
+ }
131
+
132
+ /** Check for compile Descriptor in destination native code directory.
133
+ *
134
+ * @param nativeCodePath
135
+ * The native code directory
136
+ * @return
137
+ * The optional path to the file or none
138
+ */
139
+ private def findDescriptor (nativeCodePath : Path ): Option [Path ] = {
140
+ val file = nativeCodePath.resolve(nativeProjectProps)
141
+ if (Files .exists(file)) Some (file)
142
+ else None
42
143
}
43
144
44
145
/** Finds all the native libs on the classpath.
@@ -103,7 +204,7 @@ private[scalanative] object NativeLib {
103
204
* @return
104
205
* All file paths to compile
105
206
*/
106
- def findNativePaths (workDir : Path , destPath : Path ): Seq [Path ] = {
207
+ private def findNativePaths (workDir : Path , destPath : Path ): Seq [Path ] = {
107
208
val srcPatterns = destSrcPattern(workDir, destPath)
108
209
IO .getAll(workDir, srcPatterns)
109
210
}
@@ -136,7 +237,7 @@ private[scalanative] object NativeLib {
136
237
* @return
137
238
* The destination path of the directory
138
239
*/
139
- def unpackNativeCode (nativelib : NativeLib ): Path =
240
+ private def unpackNativeCode (nativelib : NativeLib ): Path =
140
241
if (isJar(nativelib)) unpackNativeJar(nativelib)
141
242
else copyNativeDir(nativelib)
142
243
0 commit comments