Skip to content

Commit

Permalink
Attempt to use ar command for static libraries when possible (#3548)
Browse files Browse the repository at this point in the history
* Attempt to use `ar` command for static libraries when possible
* Fix ar invocation withour MRI script
* Correctly pass linker flags

(cherry picked from commit 9b1b616)
  • Loading branch information
keynmol authored and WojciechMazur committed Oct 13, 2023
1 parent a8b83bb commit 25e4b0a
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 18 deletions.
24 changes: 21 additions & 3 deletions tools/src/main/scala/scala/scalanative/build/Discover.scala
Expand Up @@ -158,14 +158,23 @@ object Discover {
private[scalanative] val docSetup =
"http://www.scala-native.org/en/latest/user/setup.html"

private[scalanative] def tryDiscover(
binaryName: String,
envPath: String
): Try[Path] = Try(discover(binaryName, envPath))

private[scalanative] def tryDiscover(
binaryName: String
): Try[Path] = Try(discover(binaryName))

/** Discover the binary path using environment variables or the command from
* the path.
*/
private[scalanative] def discover(
binaryName: String,
envPath: String
envPath: Option[String]
): Path = {
val binPath = sys.env.get(envPath)
val binPath = envPath.flatMap(sys.env.get(_))

val command: Seq[String] = {
if (Platform.isWindows) {
Expand All @@ -185,14 +194,23 @@ object Discover {
.map { p => Paths.get(p) }
.headOption
.getOrElse {
val envMessage = envPath
.map(envPath => s"or via '$envPath' environment variable")
.getOrElse("")
throw new BuildException(
s"""'$binaryName' not found in PATH or via '$envPath' environment variable.
s"""'$binaryName' not found in PATH$envMessage.
|Please refer to ($docSetup)""".stripMargin
)
}
path
}

private[scalanative] def discover(binaryName: String, envPath: String): Path =
discover(binaryName, Some(envPath))

private[scalanative] def discover(binaryName: String): Path =
discover(binaryName, None)

/** Detect the target architecture.
*
* @param clang
Expand Down
52 changes: 37 additions & 15 deletions tools/src/main/scala/scala/scalanative/build/LLVM.scala
Expand Up @@ -180,9 +180,9 @@ private[scalanative] object LLVM {
val artifactName = outpath.getFileName().toString
if (config.compilerConfig.buildTarget == BuildTarget.LibraryDynamic)
if (config.targetsLinux)
List("-Wl,-soname", artifactName)
List(s"-Wl,-soname,$artifactName")
else if (config.targetsMac)
List("-Wl,-install_name", artifactName)
List(s"-Wl,-install_name,$artifactName")
else Nil
else Nil
}
Expand Down Expand Up @@ -220,29 +220,51 @@ private[scalanative] object LLVM {
outpath: Path
)(implicit config: Config) = {
val workdir = config.workdir
val llvmAR = Discover.discover("llvm-ar", "LLVM_BIN")
val MIRScriptFile = workdir.resolve("MIRScript").toFile
val pw = new PrintWriter(MIRScriptFile)
try {
pw.println(s"CREATE ${escapeWhitespaces(outpath.abs)}")
objectPaths.foreach { path =>

val MRICompatibleAR =
Discover.tryDiscover("llvm-ar", "LLVM_BIN").toOption orElse
// MacOS ar command does not support -M flag...
Discover.tryDiscover("ar").toOption.filter(_ => config.targetsLinux)

def stageFiles(): Seq[String] = {
objectPaths.map { path =>
val uniqueName =
workdir
.relativize(path)
.toString()
.replace(File.separator, "_")
val newPath = workdir.resolve(uniqueName)
Files.move(path, newPath, StandardCopyOption.REPLACE_EXISTING)
pw.println(s"ADDMOD ${escapeWhitespaces(newPath.abs)}")
newPath.abs
}
pw.println("SAVE")
pw.println("END")
} finally pw.close()
}

val command = Seq(llvmAR.abs, "-M")
config.logger.running(command)
def useMRIScript(ar: Path) = {
val MIRScriptFile = workdir.resolve("MIRScript").toFile
val pw = new PrintWriter(MIRScriptFile)
try {
pw.println(s"CREATE ${escapeWhitespaces(config.buildPath.abs)}")
stageFiles().foreach { path =>
pw.println(s"ADDMOD ${escapeWhitespaces(path)}")
}
pw.println("SAVE")
pw.println("END")
} finally pw.close()

val command = Seq(ar.abs, "-M")
config.logger.running(command)

Process(command, config.workdir.toFile()) #< MIRScriptFile
Process(command, config.workdir.toFile()) #< MIRScriptFile
}

MRICompatibleAR match {
case None =>
val ar = Discover.discover("ar")
val command = Seq(ar.abs, "rc", config.buildPath.abs) ++ stageFiles()
config.logger.running(command)
Process(command, config.workdir.toFile())
case Some(path) => useMRIScript(path)
}
}

/** Checks the input timestamp to see if the file needs compiling. The call to
Expand Down

0 comments on commit 25e4b0a

Please sign in to comment.