Skip to content

Commit

Permalink
Attempt to use ar command for static libraries when possible (scala…
Browse files Browse the repository at this point in the history
…-native#3548)

* Attempt to use `ar` command for static libraries when possible
* Fix ar invocation withour MRI script
* Correctly pass linker flags
  • Loading branch information
keynmol committed Oct 9, 2023
1 parent 6952d99 commit 9b1b616
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 18 deletions.
19 changes: 16 additions & 3 deletions tools/src/main/scala/scala/scalanative/build/Discover.scala
Expand Up @@ -164,14 +164,18 @@ object Discover {
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 @@ -191,14 +195,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 @@ -231,9 +231,9 @@ private[scalanative] object LLVM {
val linkNameFlags =
if (config.compilerConfig.buildTarget == BuildTarget.LibraryDynamic)
if (config.targetsLinux)
List("-Wl,-soname", config.artifactName)
List(s"-Wl,-soname,${config.artifactName}")
else if (config.targetsMac)
List("-Wl,-install_name", config.artifactName)
List(s"-Wl,-install_name,${config.artifactName}")
else Nil
else Nil

Expand Down Expand Up @@ -269,29 +269,51 @@ private[scalanative] object LLVM {
objectPaths: Seq[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(config.buildPath.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 9b1b616

Please sign in to comment.