diff --git a/.github/workflows/fixtures/test-scala-cli.scala b/.github/workflows/fixtures/test-scala-cli.scala index 97af29f..5bcc2b4 100644 --- a/.github/workflows/fixtures/test-scala-cli.scala +++ b/.github/workflows/fixtures/test-scala-cli.scala @@ -1,6 +1,7 @@ //> using dep "com.armanbilge::porcupine::0.0.1" //> using platform scala-native //> using scala 3.3.1 +//> using nativeVersion 0.4.17 import porcupine.* import cats.effect.IOApp diff --git a/README.md b/README.md index 11fca9b..efe1750 100644 --- a/README.md +++ b/README.md @@ -12,10 +12,13 @@ - [SBT](#sbt) - [Mill](#mill) - [CLI](#cli) + - [`--rename` argument](#rename-argument) + - [`pass` command](#pass-command) - [`bootstrap`](#bootstrap) - - [`install`](#install) - - [`clang` and `clang++`](#clang-and-clang) - - [`scala-cli`](#scala-cli) + - [`install` command](#install-command) + - [`clang` and `clang++` commands](#clang-and-clang-commands) + - [`setup-clangd`](#setup-clangd) + - [`scala-cli` command](#scala-cli-command) - [Docker base image](#docker-base-image) - [Core](#core) - [VcpkgRootInit](#vcpkgrootinit) @@ -77,7 +80,7 @@ There are several modules of interest: You can quickly test it by running: ``` - $ cs launch com.indoorvivants.vcpkg:sn-vcpkg_3:0.0.18 -- install libpq -l -q -c + $ cs launch com.indoorvivants.vcpkg:sn-vcpkg_3:0.0.20 -- install libpq -l -q -c -I<...>/sbt-vcpkg/vcpkg-install/arm64-osx/lib/pkgconfig/../../include -L<...>/sbt-vcpkg/vcpkg-install/arm64-osx/lib/pkgconfig/../../lib -L<...>/sbt-vcpkg/vcpkg-install/arm64-osx/lib/pkgconfig/../../lib/pkgconfig/../../lib @@ -103,7 +106,7 @@ There are several modules of interest: For SBT, add this to your `project/plugins.sbt`: ```scala -addSbtPlugin("com.indoorvivants.vcpkg" % "sbt-vcpkg" % "0.0.18") +addSbtPlugin("com.indoorvivants.vcpkg" % "sbt-vcpkg" % "0.0.20") ``` And in your build.sbt: @@ -141,7 +144,7 @@ Tasks and settings (find them all by doing `help vcpkg*` in SBT shell): Add dependency to your `build.sc`: ```scala -import $ivy.`com.indoorvivants.vcpkg::mill-vcpkg:0.0.18` +import $ivy.`com.indoorvivants.vcpkg::mill-vcpkg:0.0.20` ``` And use the `VcpkgModule` mixin: @@ -152,7 +155,7 @@ import com.indoorvivants.vcpkg._ import mill._, mill.scalalib._ object example extends ScalaModule with VcpkgModule { - def scalaVersion = "3.3.1" + def scalaVersion = "3.3.3" def vcpkgDependencies = T(VcpkgDependencies("cmark", "cjson")) } ``` @@ -168,7 +171,7 @@ The Mill tasks are the same as in the SBT plugin In `project/plugins.sbt`: ```scala -addSbtPlugin("com.indoorvivants.vcpkg" % "sbt-vcpkg-native" % "0.0.18") +addSbtPlugin("com.indoorvivants.vcpkg" % "sbt-vcpkg-native" % "0.0.20") ``` In `build.sbt`: @@ -198,7 +201,7 @@ For real world usage, see [Examples](#examples). Add dependency to your `build.sc`: ```scala -import $ivy.`com.indoorvivants.vcpkg::mill-vcpkg-native:0.0.18` +import $ivy.`com.indoorvivants.vcpkg::mill-vcpkg-native:0.0.20` ``` And use the `VcpkgNativeModule` mixin: @@ -404,6 +407,25 @@ sn-vcpkg clang --manifest vcpkg.json -- test-sqlite.c All the arguments after `--` will be passed to clang/clang++ without modification (_before_ the flags calculated for dependencies) +#### `setup-clangd` + +[Clangd](https://clangd.llvm.org/) is an LSP server for C/C++. + +One of the [simplest way to configure it](https://clang.llvm.org/docs/JSONCompilationDatabase.html#alternatives) is to create a `compile_flags.txt` file in the root folder +of where your C/C++ files are located. + +For dependencies you're installing with sn-vcpkg, you can create `compile_flags.txt` by running + +``` +sn-vcpkg setup-clangd +``` + +E.g. if you want to configure your C files to work with Cairo and Sqlite3: + +``` +sn-vcpkg setup-clangd cairo sqlite3 +``` + #### `scala-cli` command This command invokes your local installation of Scala CLI (`scala-cli` must be available on PATH), diff --git a/build.sbt b/build.sbt index 1837698..68bccc6 100644 --- a/build.sbt +++ b/build.sbt @@ -25,7 +25,7 @@ val V = new { val scala212 = "2.12.18" - val scala3 = "3.3.1" + val scala3 = "3.3.3" val dirs = "26" @@ -76,7 +76,7 @@ lazy val docs = .dependsOn(core.jvm(V.scala3), cli.jvm(V.scala3)) .settings(scalaVersion := V.scala3) .settings( - mdocVariables := Map("VERSION" -> "0.0.18", "SCALA3_VERSION" -> V.scala3) + mdocVariables := Map("VERSION" -> "0.0.20", "SCALA3_VERSION" -> V.scala3) ) lazy val docsDrifted = taskKey[Boolean]("") diff --git a/docs/README.in.md b/docs/README.in.md index 624f163..9428275 100644 --- a/docs/README.in.md +++ b/docs/README.in.md @@ -12,10 +12,13 @@ - [SBT](#sbt) - [Mill](#mill) - [CLI](#cli) + - [`--rename` argument](#rename-argument) + - [`pass` command](#pass-command) - [`bootstrap`](#bootstrap) - - [`install`](#install) - - [`clang` and `clang++`](#clang-and-clang) - - [`scala-cli`](#scala-cli) + - [`install` command](#install-command) + - [`clang` and `clang++` commands](#clang-and-clang-commands) + - [`setup-clangd`](#setup-clangd) + - [`scala-cli` command](#scala-cli-command) - [Docker base image](#docker-base-image) - [Core](#core) - [VcpkgRootInit](#vcpkgrootinit) @@ -361,6 +364,25 @@ sn-vcpkg clang --manifest vcpkg.json -- test-sqlite.c All the arguments after `--` will be passed to clang/clang++ without modification (_before_ the flags calculated for dependencies) +#### `setup-clangd` + +[Clangd](https://clangd.llvm.org/) is an LSP server for C/C++. + +One of the [simplest way to configure it](https://clang.llvm.org/docs/JSONCompilationDatabase.html#alternatives) is to create a `compile_flags.txt` file in the root folder +of where your C/C++ files are located. + +For dependencies you're installing with sn-vcpkg, you can create `compile_flags.txt` by running + +``` +sn-vcpkg setup-clangd +``` + +E.g. if you want to configure your C files to work with Cairo and Sqlite3: + +``` +sn-vcpkg setup-clangd cairo sqlite3 +``` + #### `scala-cli` command This command invokes your local installation of Scala CLI (`scala-cli` must be available on PATH), diff --git a/modules/cli/src/main/scala/CommandLineApp.scala b/modules/cli/src/main/scala/CommandLineApp.scala index 01046ef..c52ec52 100644 --- a/modules/cli/src/main/scala/CommandLineApp.scala +++ b/modules/cli/src/main/scala/CommandLineApp.scala @@ -8,6 +8,9 @@ import io.circe.Codec import io.circe.CodecDerivation import io.circe.Decoder import java.io.File +import java.nio.file.Paths +import scala.util.Using +import java.io.FileWriter enum Compiler: case Clang, ClangPP @@ -34,6 +37,13 @@ enum Action: case Pass(args: Seq[String]) + case SetupClangd( + dependencies: VcpkgDependencies, + filename: String, + rename: Map[String, String], + force: Boolean + ) + case Bootstrap end Action @@ -125,6 +135,15 @@ object Options extends VcpkgPluginImpl: ) .orFalse + private def force(description: String) = Opts + .flag( + long = "force", + short = "f", + visibility = Visibility.Normal, + help = description + ) + .orFalse + private val quiet = Opts .flag( long = "quiet", @@ -171,8 +190,24 @@ object Options extends VcpkgPluginImpl: .map(deps => VcpkgDependencies.apply(deps*)) ) + private val compileFlagsFilename = Opts + .option[String]( + "out", + help = + "Path to file where flags will be written (default: ./compile_flags.txt)" + ) + .withDefault("compile_flags.txt") + private val actionInstall = (deps, out, rename).mapN(Action.Install.apply) + private val actionSetupClangd = + ( + deps, + compileFlagsFilename, + rename, + force("Overwrite the file with flags even if it exists") + ).mapN(Action.SetupClangd.apply) + val logger = ExternalLogger( debug = scribe.debug(_), info = scribe.info(_), @@ -203,6 +238,14 @@ object Options extends VcpkgPluginImpl: (actionInstall.map(SuspendedAction.immediate), configOpts).tupled ) + private val setupClangd = + Opts.subcommand( + "setup-clangd", + "Setup Clangd (e.g. with compile_flags.txt)" + )( + (actionSetupClangd.map(SuspendedAction.immediate), configOpts).tupled + ) + private val bootstrap = Opts.subcommand("bootstrap", "Bootstrap vcpkg")( configOpts.map(SuspendedAction.immediate(Action.Bootstrap) -> _) @@ -256,7 +299,13 @@ object Options extends VcpkgPluginImpl: val opts = Command(name, header)( - install orElse bootstrap orElse clang orElse clangPP orElse scalaCli orElse pass + install orElse + bootstrap orElse + clang orElse + clangPP orElse + scalaCli orElse + pass orElse + setupClangd ) end Options @@ -391,6 +440,33 @@ object VcpkgCLI extends VcpkgPluginImpl, VcpkgPluginNativeImpl: result.filter((k, v) => allDeps.contains(k)), rename ).map(_.get).foreach(println) + case Action.SetupClangd(deps, output, rename, force) => + val path = Paths.get(output).toAbsolutePath() + if path.toFile().isFile() && !force then + sys.error( + s"Path [$path] already exists - to overwrite it, please pass `-f`/`--force` flag" + ) + + val result = vcpkgInstallImpl(deps, manager, logger) + + import io.circe.parser.decode + import C.given + + val allDeps = + deps.dependencies(str => + decode[VcpkgManifestFile](str).fold(throw _, identity) + ) + + val flags = computeNativeFlags( + OutputOptions(compile = true, linking = true), + allDeps, + result.filter((k, v) => allDeps.contains(k)), + rename + ).map(_.get) + + Using.resource(new FileWriter(path.toFile())): fw => + fw.write(flags.mkString(System.lineSeparator())) + case Action.InvokeCompiler(compiler, deps, rename, rest) => val result = vcpkgInstallImpl(deps, manager, logger) import io.circe.parser.decode