@@ -26,7 +26,8 @@ import scala.build.interactive.InteractiveFileOps
26
26
import scala .build .internal .Util .*
27
27
import scala .build .internal .resource .NativeResourceMapper
28
28
import scala .build .internal .{Runner , ScalaJsLinkerConfig }
29
- import scala .build .options .{BuildOptions , JavaOpt , PackageType , Platform }
29
+ import scala .build .options .PackageType .Native
30
+ import scala .build .options .{BuildOptions , JavaOpt , PackageType , Platform , ScalaNativeTarget }
30
31
import scala .cli .CurrentParams
31
32
import scala .cli .commands .OptionsHelper .*
32
33
import scala .cli .commands .doc .Doc
@@ -198,36 +199,54 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
198
199
// TODO When possible, call alreadyExistsCheck() before compiling stuff
199
200
200
201
def extension = packageType match {
201
- case PackageType .LibraryJar => " .jar"
202
- case PackageType .SourceJar => " .jar"
203
- case PackageType .DocJar => " .jar"
204
- case _ : PackageType .Assembly => " .jar"
205
- case PackageType .Spark => " .jar"
206
- case PackageType .Js => " .js"
207
- case PackageType .Debian => " .deb"
208
- case PackageType .Dmg => " .dmg"
209
- case PackageType .Pkg => " .pkg"
210
- case PackageType .Rpm => " .rpm"
211
- case PackageType .Msi => " .msi"
212
- case PackageType .Native if Properties .isWin => " .exe"
202
+ case PackageType .LibraryJar => " .jar"
203
+ case PackageType .SourceJar => " .jar"
204
+ case PackageType .DocJar => " .jar"
205
+ case _ : PackageType .Assembly => " .jar"
206
+ case PackageType .Spark => " .jar"
207
+ case PackageType .Js => " .js"
208
+ case PackageType .Debian => " .deb"
209
+ case PackageType .Dmg => " .dmg"
210
+ case PackageType .Pkg => " .pkg"
211
+ case PackageType .Rpm => " .rpm"
212
+ case PackageType .Msi => " .msi"
213
+
214
+ case PackageType .Native .Application =>
215
+ if Properties .isWin then " .exe" else " "
216
+ case PackageType .Native .LibraryDynamic =>
217
+ if Properties .isWin then " .dll" else if Properties .isMac then " .dylib" else " .so"
218
+ case PackageType .Native .LibraryStatic =>
219
+ if Properties .isWin then " .lib" else " .a"
220
+
213
221
case PackageType .GraalVMNativeImage if Properties .isWin => " .exe"
214
222
case _ if Properties .isWin => " .bat"
215
223
case _ => " "
216
224
}
217
225
218
226
def defaultName = packageType match {
219
- case PackageType .LibraryJar => " library.jar"
220
- case PackageType .SourceJar => " source.jar"
221
- case PackageType .DocJar => " scaladoc.jar"
222
- case _ : PackageType .Assembly => " app.jar"
223
- case PackageType .Spark => " job.jar"
224
- case PackageType .Js => " app.js"
225
- case PackageType .Debian => " app.deb"
226
- case PackageType .Dmg => " app.dmg"
227
- case PackageType .Pkg => " app.pkg"
228
- case PackageType .Rpm => " app.rpm"
229
- case PackageType .Msi => " app.msi"
230
- case PackageType .Native if Properties .isWin => " app.exe"
227
+ case PackageType .LibraryJar => " library.jar"
228
+ case PackageType .SourceJar => " source.jar"
229
+ case PackageType .DocJar => " scaladoc.jar"
230
+ case _ : PackageType .Assembly => " app.jar"
231
+ case PackageType .Spark => " job.jar"
232
+ case PackageType .Js => " app.js"
233
+ case PackageType .Debian => " app.deb"
234
+ case PackageType .Dmg => " app.dmg"
235
+ case PackageType .Pkg => " app.pkg"
236
+ case PackageType .Rpm => " app.rpm"
237
+ case PackageType .Msi => " app.msi"
238
+
239
+ case PackageType .Native .Application =>
240
+ if Properties .isWin then " app.exe" else " app"
241
+
242
+ case PackageType .Native .LibraryDynamic =>
243
+ if Properties .isWin then " library.dll"
244
+ else if Properties .isMac then " library.dylib"
245
+ else " library.so"
246
+
247
+ case PackageType .Native .LibraryStatic =>
248
+ if Properties .isWin then " library.lib" else " library.a"
249
+
231
250
case PackageType .GraalVMNativeImage if Properties .isWin => " app.exe"
232
251
case _ if Properties .isWin => " app.bat"
233
252
case _ => " app"
@@ -363,8 +382,20 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
363
382
case PackageType .Js =>
364
383
value(buildJs(build, destPath, mainClassOpt, logger))
365
384
366
- case PackageType .Native =>
367
- val cachedDest = value(buildNative(build, value(mainClass), logger))
385
+ case tpe : PackageType .Native =>
386
+ import PackageType .Native .*
387
+ val mainClassO =
388
+ tpe match
389
+ case Application => Some (value(mainClass))
390
+ case _ => None
391
+
392
+ val cachedDest = value(buildNative(
393
+ build = build,
394
+ mainClass = mainClassO,
395
+ targetType = tpe,
396
+ destPath = Some (destPath),
397
+ logger = logger
398
+ ))
368
399
if (force) os.copy.over(cachedDest, destPath, createFolders = true )
369
400
else os.copy(cachedDest, destPath, createFolders = true )
370
401
destPath
@@ -631,7 +662,14 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
631
662
case Platform .JVM => value(bootstrap(build, appPath, mainClass, () => Right (()), logger))
632
663
case Platform .JS => buildJs(build, appPath, Some (mainClass), logger)
633
664
case Platform .Native =>
634
- val dest = value(buildNative(build, mainClass, logger))
665
+ val dest =
666
+ value(buildNative(
667
+ build = build,
668
+ mainClass = Some (mainClass),
669
+ targetType = PackageType .Native .Application ,
670
+ destPath = None ,
671
+ logger = logger
672
+ ))
635
673
os.copy(dest, appPath)
636
674
}
637
675
@@ -959,7 +997,9 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
959
997
960
998
def buildNative (
961
999
build : Build .Successful ,
962
- mainClass : String ,
1000
+ mainClass : Option [String ], // when building a static/dynamic library, we don't need a main class
1001
+ targetType : PackageType .Native ,
1002
+ destPath : Option [os.Path ],
963
1003
logger : Logger
964
1004
): Either [BuildException , os.Path ] = either {
965
1005
val dest = build.inputs.nativeWorkDir / s " main ${if (Properties .isWin) " .exe" else " " }"
@@ -980,9 +1020,26 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
980
1020
Nil
981
1021
val pythonCliOptions = pythonLdFlags.flatMap(f => Seq (" --linking-option" , f)).toList
982
1022
1023
+ val libraryLinkingOptions : Seq [String ] =
1024
+ Option .when(targetType != PackageType .Native .Application ) {
1025
+ /* If we are building a library, we make sure to change the name
1026
+ that the linker will put into the loading path - otherwise
1027
+ the built library will depend on some internal path within .scala-build
1028
+ */
1029
+
1030
+ destPath.flatMap(_.lastOpt).toSeq.flatMap { filename =>
1031
+ val linkerOption =
1032
+ if Properties .isLinux then s " -Wl,-soname, $filename" else s " -Wl,-install_name, $filename"
1033
+ Seq (" --linking-option" , linkerOption)
1034
+ }
1035
+ }.toSeq.flatten
1036
+
1037
+ import PackageType .Native .*
1038
+
983
1039
val allCliOptions = pythonCliOptions ++
984
1040
cliOptions ++
985
- Seq (" --main" , mainClass)
1041
+ libraryLinkingOptions ++
1042
+ mainClass.toSeq.flatMap(m => Seq (" --main" , m))
986
1043
987
1044
val nativeWorkDir = build.inputs.nativeWorkDir
988
1045
os.makeDir.all(nativeWorkDir)
@@ -1040,7 +1097,14 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
1040
1097
lazy val validPackageScalaJS =
1041
1098
Seq (PackageType .Js , PackageType .LibraryJar , PackageType .SourceJar , PackageType .DocJar )
1042
1099
lazy val validPackageScalaNative =
1043
- Seq (PackageType .Native , PackageType .LibraryJar , PackageType .SourceJar , PackageType .DocJar )
1100
+ Seq (
1101
+ PackageType .LibraryJar ,
1102
+ PackageType .SourceJar ,
1103
+ PackageType .DocJar ,
1104
+ PackageType .Native .Application ,
1105
+ PackageType .Native .LibraryDynamic ,
1106
+ PackageType .Native .LibraryStatic
1107
+ )
1044
1108
1045
1109
forcedPackageTypeOpt -> build.options.platform.value match {
1046
1110
case (Some (forcedPackageType), _) => Right (forcedPackageType)
@@ -1061,14 +1125,24 @@ object Package extends ScalaCommand[PackageOptions] with BuildCommandHelpers {
1061
1125
))
1062
1126
validatedPackageType.getOrElse(Right (PackageType .Js ))
1063
1127
case (_, Platform .Native ) =>
1128
+ val specificNativePackageType =
1129
+ import ScalaNativeTarget .*
1130
+ build.options.scalaNativeOptions.buildTargetStr.flatMap(fromString).map {
1131
+ case Application => PackageType .Native .Application
1132
+ case LibraryDynamic => PackageType .Native .LibraryDynamic
1133
+ case LibraryStatic => PackageType .Native .LibraryStatic
1134
+ }
1135
+
1064
1136
val validatedPackageType =
1065
- for (basePackageType <- basePackageTypeOpt)
1066
- yield
1067
- if (validPackageScalaNative.contains(basePackageType)) Right (basePackageType)
1068
- else Left (new MalformedCliInputError (
1069
- s " Unsupported package type: $basePackageType for Scala Native. "
1070
- ))
1071
- validatedPackageType.getOrElse(Right (PackageType .Native ))
1137
+ for
1138
+ basePackageType <- specificNativePackageType orElse basePackageTypeOpt
1139
+ yield
1140
+ if (validPackageScalaNative.contains(basePackageType)) Right (basePackageType)
1141
+ else Left (new MalformedCliInputError (
1142
+ s " Unsupported package type: $basePackageType for Scala Native. "
1143
+ ))
1144
+
1145
+ validatedPackageType.getOrElse(Right (PackageType .Native .Application ))
1072
1146
case _ => Right (basePackageTypeOpt.getOrElse(PackageType .Bootstrap ))
1073
1147
}
1074
1148
}
0 commit comments