Giter Club home page Giter Club logo

sn-vcpkg's Introduction

sn-vcpkg

Utilities and build tools to work with vcpkg C/C++ dependency manager

If you are in a rant-reading mood, please refer to motivation.

If you want to update this documentation file, don't edit it directly - edit docs/README.in.md and run sbt updateDocs. It's annoying, but this document contains compiled snippets of code which I want to prevent from going out of date

Usage TLDR: most likely you want to take a look at SBT plugin or Mill plugin

Vcpkg and native dependencies 101

  • By native dependencies we mean C/C++ libraries
  • Usually distributed as sources (but some distributions contain pre-built artifacts, like gtk)
  • Usually built on user's machine
  • Contain following artifact types:
    • Binary
      • dynamic libraries (needed at runtime and linktime)
      • static libraries (needed at linktime)
    • C/C++ headers (optional, needed for compile time)
    • pkg-config files *.pc (optional, provide a recipe for constructing the correct clang/gcc flags to use the dependency)
  • vcpkg contains lots and lots of pre-made recipes for popular libraries, with aim to work on Linux, MacOS, and Windows
  • vcpkg works as both a CLI installer (vcpkg install cjson) and as manifest installer (vcpkg install vcpkg.json) with dependencies specified in a JSON file :)
  • vcpkg can bootstrap itself from a cloned repo :)
  • vcpkg can install libraries into a custom location (instead of system-wide) making caching and isolation easier :)

:) - this project does it for you

Usage

Examples

Summary

There are several modules of interest:

  1. core - contains all the tool-agnostic logic for bootstrapping, invoking, and communicating with vcpkg. This module is the meat on the proverbial bones, the plugins and the CLI merely invoke it.

  2. cli - contains a very barebones CLI wrapper over core with dubious value proposition: as it delegates fully to the core module, it uses the same defaults, location, and installation logic as the build tooling would use.

    As such, it's possible to invoke the CLI prior to launching the build, to preinstall the necessary dependencies (as in a separate layer in a Docker container), and to be sure that the same dependencies definition in a build tool of your choosing (SBT or Mill) will immediately find the packages where they're supposed to be.

    You can quickly test it by running:

     $ cs launch com.indoorvivants.vcpkg:sn-vcpkg_3:0.0.18 -- 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
     -lpq
     -lpgcommon
     -lpgport
     -lm
     -lssl
     -lcrypto
    

    This particular example

    1. Installs libpq (C interface to Postgres)
    2. Outputs compilation and linking flags for Clang/GCC one per line

    As part of the process, the CLI will also bootstrap vcpkg if it cannot find it in the predetermined location (see below)

  3. SBT plugin and Mill plugin that just install the dependencies

  4. SBT and Mill plugins that additionally integrate with respective Scala Native plugins, see Scala Native integration

SBT plugin

For SBT, add this to your project/plugins.sbt:

addSbtPlugin("com.indoorvivants.vcpkg" % "sbt-vcpkg" % "0.0.18")

And in your build.sbt:

enablePlugins(VcpkgPlugin)

vcpkgDependencies := VcpkgDependencies(
  "cjson",
  "cmark"
)

After that, run vcpkgInstall and vcpkg will be bootstrapped and dependencies installed.

Tasks and settings (find them all by doing help vcpkg* in SBT shell):

  • vcpkgDependencies - see VcpkgDependencies

  • vcpkgInstall - performs bootstrap and installation of all specified dependencies. Triggers bootstrap

  • vcpkgRootInit - see VcpkgRootInit

  • vcpkgRoot - the actual location of vcpkg installation, computed using vcpkgRootInit

  • vcpkgInstallDir - the location where installed vcpkg artifacts will be placed - by default it's a cache folder located according to OS-specific guidelines

  • vcpkgBinary - the location of just the vcpkg binary itself. Triggers bootstrap

  • vcpkgConfigurator - see VcpkgConfigurator

  • vcpkgRun - invoke the vcpkg CLI directly

Mill plugin

Add dependency to your build.sc:

import $ivy.`com.indoorvivants.vcpkg::mill-vcpkg:0.0.18`

And use the VcpkgModule mixin:

import com.indoorvivants.vcpkg.millplugin.VcpkgModule
import com.indoorvivants.vcpkg._

import mill._, mill.scalalib._
object example extends ScalaModule with VcpkgModule {
  def scalaVersion = "3.3.1"
  def vcpkgDependencies = T(VcpkgDependencies("cmark", "cjson"))
}

and use vcpkgInstall to install vcpkg dependencies.

The Mill tasks are the same as in the SBT plugin

Scala Native integration

SBT

In project/plugins.sbt:

addSbtPlugin("com.indoorvivants.vcpkg" % "sbt-vcpkg-native" % "0.0.18")

In build.sbt:

enablePlugins(VcpkgNativePlugin, ScalaNativePlugin)

vcpkgDependencies := VcpkgDependencies(
  "cjson",
  "cmark",
)

vcpkgNativeConfig ~= {
  _.withRenamedLibraries(
    Map("cjson" -> "libcjson", "cmark" -> "libcmark")
  )
}

With that, if you run the project, vcpkg dependencies will be automatically installed and the NativeConfig will be configured so that compilation and linking will succeed.

For real world usage, see Examples.

Mill

Add dependency to your build.sc:

import $ivy.`com.indoorvivants.vcpkg::mill-vcpkg-native:0.0.18`

And use the VcpkgNativeModule mixin:

import com.indoorvivants.vcpkg.millplugin.native.VcpkgNativeModule
import com.indoorvivants.vcpkg.millplugin.VcpkgModule
import com.indoorvivants.vcpkg._

import mill._, mill.scalalib._
object example extends VcpkgNativeModule {
  def vcpkgDependencies = T(VcpkgDependencies("cjson", "cmark"))
  def scalaVersion = T("3.2.2")
  def scalaNativeVersion = T("0.4.10")

  override def vcpkgNativeConfig =
    T(super
        .vcpkgNativeConfig()
        .addRenamedLibrary("cjson", "libcjson")
        .addRenamedLibrary("cmark", "libcmark")
    )
}

CLI

This is a very thin interface to the Core module, designed mostly for demonstration purposes or to install dependencies in CI/containers, without launching the SBT/Mill project.

Installation with Coursier:

$ cs install sn-vcpkg --channel https://cs.indoorvivants.com/i.json

Usage example:

$ sn-vcpkg install libgit2 -l -c

This will install libgit2 package, and output linking flags (-l) and compilation flags (-c), one per line.

--rename argument

All commands accept a --rename name1=alt_name1,name2=alt_name2 because for some packages in vcpkg the name of the package and the name under which it is installed in pkg-config might be different.

For example, curl is one of those. Running the simple command will complain that pkg-config configuration was not found

$ sn-vcpkg install curl -l -c 
...
    [vcpkg stderr] Package curl was not found in the pkg-config search path.
    [vcpkg stderr] Perhaps you should add the directory containing `curl.pc'
    [vcpkg stderr] to the PKG_CONFIG_PATH environment variable
    [vcpkg stderr] No package 'curl' found
...

And the approximated arguments it will output will be insufficient.

But if you ask to rename it during resolution:

$ sn-vcpkg install -l -c curl --rename curl=libcurl

Then you get the correct flags. The name of the argument is not great, but it's a bandaid for an equally not great gotcha in vcpkg so I think we're even.

pass command

If you just want to invoke the vcpkg CLI, you can do so with the pass command:

sn-vcpkg pass -- help

Arguments after -- will be passed directly to vcpkg, and its STDOUT output will be printed to STDOUT.

bootstrap

Only bootstrap vcpkg if necessary, without installing anything

Usage: sn-vcpkg bootstrap [--vcpkg-root-manual <location> [--no-bootstrap] | --vcpkg-root-env <env-var> [--no-bootstrap] | --no-bootstrap] [--vcpkg-install <dir>] [--no-bootstrap] [--verbose] [--quiet]

Bootstrap vcpkg

Options and flags:
    --help
        Display this help text.
    --vcpkg-root-manual <location>
        Initialise vcpkg in this location
    --no-bootstrap
        Allow bootstrapping vcpkg from scratch
    --vcpkg-root-env <env-var>
        Pick up vcpkg root from the environment variable
    --vcpkg-install <dir>
        folder where packages will be installed
    --verbose, -v
        Verbose logging
    --quiet, -q
        Only error logging

install command

Install one or several dependencies, by name or from a manifest file, and optionally output linking/compilation flags for all of them.

Examples:

  • sn-vcpkg install libgit2 cjson -l -c
  • sn-vcpkg install --manifest vcpkg.json -l -c
Usage:
    sn-vcpkg install --manifest <string> [--output-compilation] [--output-linking] [--rename <spec1,spec2,spec3>] [--vcpkg-root-manual <location> [--no-bootstrap] | --vcpkg-root-env <env-var> [--no-bootstrap] | --no-bootstrap] [--vcpkg-install <dir>] [--no-bootstrap] [--verbose] [--quiet]
    sn-vcpkg install [--output-compilation] [--output-linking] [--rename <spec1,spec2,spec3>] [--vcpkg-root-manual <location> [--no-bootstrap] | --vcpkg-root-env <env-var> [--no-bootstrap] | --no-bootstrap] [--vcpkg-install <dir>] [--no-bootstrap] [--verbose] [--quiet] <dep>...

Install a list of vcpkg dependencies

Options and flags:
    --help
        Display this help text.
    --manifest <string>
        vcpkg manifest file
    --output-compilation, -c
        Output (to STDOUT) compilation flags for installed libraries, one per line
    --output-linking, -l
        Output (to STDOUT) linking flags for installed libraries, one per line
    --rename <spec1,spec2,spec3>
        rename packages when looking up their flags in pkg-config
        e.g. --rename curl=libcurl,cjson=libcjson
    --vcpkg-root-manual <location>
        Initialise vcpkg in this location
    --no-bootstrap
        Allow bootstrapping vcpkg from scratch
    --vcpkg-root-env <env-var>
        Pick up vcpkg root from the environment variable
    --vcpkg-install <dir>
        folder where packages will be installed
    --verbose, -v
        Verbose logging
    --quiet, -q
        Only error logging

clang and clang++ commands

These commands invoke clang or clang++ with all the configuration flags required 1 to run the specified dependencies.

For example, say you have a snippet of C code that needs sqlite3 dependency:

#include <stdio.h>
#include <sqlite3.h> 

int main(int argc, char* argv[]) {
   sqlite3 *db;
   char *zErrMsg = 0;
   int rc;

   rc = sqlite3_open("test.db", &db);

   if( rc ) {
      fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
      return(0);
   } else {
      fprintf(stderr, "Opened database successfully\n");
   }
   sqlite3_close(db);
}

You can compile it directly by running

sn-vcpkg clang sqlite3 -- test-sqlite.c

Or if you have a vcpkg manifest file:

{
 "name": "my-application",
 "version": "0.15.2",
 "dependencies": ["sqlite3"]
}

You can use that as well:

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)

scala-cli command

This command invokes your local installation of Scala CLI (scala-cli must be available on PATH), and passes all the flags required by the specified dependencies 1.

For example, say you have a Scala CLI script using Porcupine, a cross-platform functional library for Sqlite3:

scala-cli-sqlite3.scala

//> using dep "com.armanbilge::porcupine::0.0.1"
//> using platform scala-native
//> using scala 3.3.1

import porcupine.*
import cats.effect.IOApp
import cats.effect.IO
import cats.syntax.all.*
import scodec.bits.ByteVector

import Codec.*

object Test extends IOApp.Simple:
  val run =
    Database
      .open[IO](":memory:")
      .use: db =>
        db.execute(sql"create table porcupine (n, i, r, t, b);".command) *>
          db.execute(
            sql"insert into porcupine values(${`null`}, $integer, $real, $text, $blob);".command,
            (None, 42L, 3.14, "quill-pig", ByteVector(0, 1, 2, 3))
          ) *>
          db.unique(
            sql"select b, t, r, i, n from porcupine;"
              .query(blob *: text *: real *: integer *: `null` *: nil)
          ).flatTap(IO.println)
      .void
end Test

To run it with Scala Native, you must have sqlite3 native dependency installed and configured, along with correct flags passed to Scala Native.

You can run the script like this:

sn-vcpkg scala-cli sqlite3 -- run scala-cli-sqlite3.scala

The sn-vcpkg CLI will add the required --native-compile/--native-linking flags to the end of your argument list automatically.

Docker base image

Because of the sheer number of different tools required to install packages from vcpkg (like libtool, curl, zip/unzip, autoconf, make, cmake, etc.) we provide a Docker base image that contains some of them. The list is by no means exhaustive and a PR adding more will be happily accepted.

The docker image contains the following:

  1. Ubuntu 22.04 base

  2. OpenJDK 17

  3. Tools like

    clang zip unzip tar make cmake autoconf ninja-build
    pkg-config git libtool curl
    
  4. SBT (1.9.x)

  5. Coursier

  6. sn-vpkg CLI itself

Te purpose of this docker image is to be used as a baser on CI, e.g.:

# huge container we use only for builds 
FROM keynmol/sn-vcpkg:latest as dev

# install your application's dependencies
RUN sn-vcpkg install curl

WORKDIR /workdir

# copy your sources into container
COPY . .

# run the build of your scala native application
RUN sbt myApp/nativeLink

# This is the actual, much smaller container that will run the app
FROM <runtime-container> 

# copy the built app from the dev container
COPY --from=dev /workdir/build/server /usr/bin/server

ENTRYPOINT ["server"]

Core

VcpkgRootInit

Defines the location where Vcpkg will be bootstrapped.

Variations (with defaults):

  • (default) SystemCache(allowBootstrap = true) - will bootstrap (if allowed) vcpkg in a system cache directory, decided by dirs-dev library

  • FromEnv(name = "VCPKG_ROOT", allowBootstrap = true) - will bootstrap (if allowed) in a location specified by an environment variable name

  • Manual(file: File, allowBootstrap = true) - will bootstrap (if allowed) in a location specified by file

VcpkgNativeConfig

This configuration object controls various aspects of how sn-vcpkg manipulates Scala Native's NativeConfig object to add linking and compilation arguments from installed vcpkg dependencies.

Defaults

VcpkgNativeConfig()
// res2: VcpkgNativeConfig = Vcpkg NativeConfig: 
//   | approximate = true
//   | autoConfigure = true
//   | prependCompileOptions = true
//   | prependLinkingOptions = true
//   | renamedLibraries = 
//   | staticLinking = false

approximate - whether to approximate compilation/linking flags in case pkg-config file is not shipped with the library

VcpkgNativeConfig().withApproximate(true)

autoConfigure - whether to automatically configure Scala Native's NativeConfig with flags for all specified vcpkg dependencies

VcpkgNativeConfig().withAutoConfigure(true)

prependCompileOptions - whether to prepend compilation flags derived from vcpkg before the flags that Scala Native puts.

It can be useful because Scala Native adds certain system locations to linking flags by default, and these might have non-vcpkg versions of some of your dependencies

VcpkgNativeConfig().withPrependCompileOptions(true)

prependLinkingOptions - whether to prepend linking flags derived from vcpkg before the flags that Scala Native puts.

VcpkgNativeConfig().withPrependLinkingOptions(true)

renamedLibraries - a mapping between vcpkg package names and the names under which the pkg-config files are installed - those can be different for no good reason whatsoever.

// Completely overwrite
VcpkgNativeConfig().withRenamedLibraries(Map("cjson" -> "libcjson", "cmark" -> "libcmark"))
// res7: VcpkgNativeConfig = Vcpkg NativeConfig: 
//   | approximate = true
//   | autoConfigure = true
//   | prependCompileOptions = true
//   | prependLinkingOptions = true
//   | renamedLibraries = cjson -> libcjson, cmark -> libcmark
//   | staticLinking = false

// Append only
VcpkgNativeConfig().addRenamedLibrary("cjson", "libcjson")
// res8: VcpkgNativeConfig = Vcpkg NativeConfig: 
//   | approximate = true
//   | autoConfigure = true
//   | prependCompileOptions = true
//   | prependLinkingOptions = true
//   | renamedLibraries = cjson -> libcjson
//   | staticLinking = false

VcpkgDependencies

Specification for vcpkg dependencies. Can be either:

  • a simple list of dependency names:
VcpkgDependencies("cmark", "cjson")
// res9: VcpkgDependencies = Names(
//   deps = List(
//     Dependency(name = "cmark", features = Set()),
//     Dependency(name = "cjson", features = Set())
//   )
// )
  • a path to manifest file:
VcpkgDependencies(new java.io.File("./vcpkg.json"))
// res10: VcpkgDependencies = ManifestFile(path = ./vcpkg.json)
  • a list of detailed dependency specs:
VcpkgDependencies.Names(List(Dependency("libpq", Set("arm-build")), Dependency.parse("cpprestsdk[boost]")))
// res11: Names = Names(
//   deps = List(
//     Dependency(name = "libpq", features = Set("arm-build")),
//     Dependency(name = "cpprestsdk", features = Set("boost"))
//   )
// )

VcpkgConfigurator

While this class has useful methods of its own (see API docs), its main purpose is to provide a configured PkgConfig instance

PkgConfig

API docs

A thin pre-configured (by the build tool) wrapper around pkg-config tool.

Footnotes

  1. as long as the dependencies themselves provide a well configured pkg-config file, of course 2

sn-vcpkg's People

Contributors

baccata avatar indoorvivants-steward[bot] avatar jd557 avatar keynmol avatar mergify[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar

Forkers

baccata jd557

sn-vcpkg's Issues

Clone vcpkg into a global cache location

Vcpkg takes a long time to clone, and if you have multiple projects it will clone them into per-project target folder.

It'd be better to have the repo itself in a global cache location, and keep the installation folders local per-project (to isolate them).

For choosing the right cache folder on any platform, I believe this library is the accepted standard: https://github.com/dirs-dev/directories-jvm

Supply --recurse flag

For large projects (like gtk), apparently vcpkg will fail unless you tell it to go ahead

Inexistent vcpkgNativeApprxomate config

Typo aside, there's a warning in

logger.warn(
s"Compilation flags for `${nameDescr}` dependency were approximate, and might be incorrect. " +
"If you want to disable approximation, set `vcpkgNativeApprxomate := false`"
)
and
logger.warn(
s"Linking flags for `$nameDescr` dependency were approximated, and might be incorrect. " +
"If you want to disable approximation, set `vcpkgNativeApprxomate := false`"
)
recommending to set vcpkgNativeApprxomate := false, but no setting like that seems to exist.

Run example as part of CI on MacOS

We are already run the hermetically sealed example on Linux, using Docker.

On Mac, we should just

  1. Publish sbt-vcpkg and dump the version
  2. use dumped version to run the example cd example && SBT_VCPKG_VERSION=<dumped-version> sbt run

Should it be it, really. If sbt-vcpkg is worth its money :)

Jar vcpkg.json support

If we can find a vcpkg.json in some specified location in the jar of one of the dependencies, we should merge the configuration from that vcpkg.json with what we have locally.

Depends on #47.

After that, I believe we should provide some facilities for library authors to easier configure the two following things:

  1. vcpkg-json-location attribute in META-INF/MANIFEST.MF in the jar, which points to the relative location of the vcpkg.json in the jar
  2. the file itself

I believe just automating addition of attributes and vcpkg.json (copied from the location specified in the module)

  • core nothing to be done I believe, apart from the constant for the attribute name
  • sbt-vcpkg VcpkgLibraryPlugin which just does the things above
  • mill-vcpkg not sure how best to handle it

`scala.MatchError: List(A suitable version of cmake was not found (required v3.24.0). Downloading portable cmake v3.24.0...)`

[error] scala.MatchError: List(A suitable version of cmake was not found (required v3.24.0). Downloading portable cmake v3.24.0...) (of class scala.collection.immutable.$colon$colon)
[error]         at com.indoorvivants.vcpkg.Vcpkg$Dependencies$.$anonfun$parse$1(Vcpkg.scala:148)
[error]         at scala.collection.TraversableLike.$anonfun$map$1(TraversableLike.scala:286)
[error]         at scala.collection.Iterator.foreach(Iterator.scala:943)
[error]         at scala.collection.Iterator.foreach$(Iterator.scala:943)
[error]         at scala.collection.AbstractIterator.foreach(Iterator.scala:1431)
[error]         at scala.collection.IterableLike.foreach(IterableLike.scala:74)
[error]         at scala.collection.IterableLike.foreach$(IterableLike.scala:73)
[error]         at scala.collection.AbstractIterable.foreach(Iterable.scala:56)
[error]         at scala.collection.TraversableLike.map(TraversableLike.scala:286)
[error]         at scala.collection.TraversableLike.map$(TraversableLike.scala:279)
[error]         at scala.collection.AbstractTraversable.map(Traversable.scala:108)
[error]         at com.indoorvivants.vcpkg.Vcpkg$Dependencies$.parse(Vcpkg.scala:147)
[error]         at com.indoorvivants.vcpkg.Vcpkg.dependencyInfo(Vcpkg.scala:79)
[error]         at com.indoorvivants.vcpkg.VcpkgPluginImpl.$anonfun$vcpkgInstallImpl$2(VcpkgPluginImpl.scala:41)
[error]         at scala.collection.TraversableLike.$anonfun$flatMap$1(TraversableLike.scala:293)
[error]         at scala.collection.immutable.Set$Set1.foreach(Set.scala:141)
[error]         at scala.collection.TraversableLike.flatMap(TraversableLike.scala:293)
[error]         at scala.collection.TraversableLike.flatMap$(TraversableLike.scala:290)
[error]         at scala.collection.AbstractTraversable.flatMap(Traversable.scala:108)
[error]         at com.indoorvivants.vcpkg.VcpkgPluginImpl.vcpkgInstallImpl(VcpkgPluginImpl.scala:40)
[error]         at com.indoorvivants.vcpkg.VcpkgPluginImpl.vcpkgInstallImpl$(VcpkgPluginImpl.scala:32)
[error]         at com.indoorvivants.vcpkg.sbt.VcpkgPlugin$.vcpkgInstallImpl(VcpkgPlugin.scala:16)
[error]         at com.indoorvivants.vcpkg.sbt.VcpkgPlugin$.$anonfun$projectSettings$15(VcpkgPlugin.scala:67)
[error]         at scala.Function1.$anonfun$compose$1(Function1.scala:49)
[error]         at sbt.internal.util.$tilde$greater.$anonfun$$u2219$1(TypeFunctions.scala:62)
[error]         at sbt.std.Transform$$anon$4.work(Transform.scala:68)
[error]         at sbt.Execute.$anonfun$submit$2(Execute.scala:282)
[error]         at sbt.internal.util.ErrorHandling$.wideConvert(ErrorHandling.scala:23)
[error]         at sbt.Execute.work(Execute.scala:291)
[error]         at sbt.Execute.$anonfun$submit$1(Execute.scala:282)
[error]         at sbt.ConcurrentRestrictions$$anon$4.$anonfun$submitValid$1(ConcurrentRestrictions.scala:265)
[error]         at sbt.CompletionService$$anon$2.call(CompletionService.scala:64)
[error]         at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
[error]         at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:539)
[error]         at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
[error]         at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
[error]         at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
[error]         at java.base/java.lang.Thread.run(Thread.java:833)
[error] (ioNative / vcpkgInstall) scala.MatchError: List(A suitable version of cmake was not found (required v3.24.0). Down

Provide a Scala Native plugin

Right now I have 3 versions of vcpkgNativeConfig laying about:

  1. https://github.com/keynmol/twotm8/blob/main/build.sbt#L200
  2. https://github.com/indoorvivants/sn-roguelike/blob/main/build.sbt#L70 (sort of, but same purpose)
  3. https://github.com/indoorvivants/sn-bindgen-examples/blob/main/build.sbt#L237
  4. https://github.com/indoorvivants/roach/blob/main/build.sbt#L51 (this is the most up-to-date, use this for reference)

What it does is pretty simple, but there are important caveats:

  1. Not all libraries have pkg-config - all we can do is speculatively add library files and header paths and sort of hope for the best

  2. The linking arguments from Scala Native's default config need to come after the arguments from vcpkg.

    If you have a libpq.dylib installed globally, then SN will gladly link against the dynamic version, instead of the static one available literally 2 arguments over.

  3. When falling back to guesswork, we need to use the transitive closure of dependencies specified in the module - pkg-config files already use that information, but if there's no .pc files we need to do it manually.

To that end I believe we should:

  • core Provide a vcpkgNativeConfigure(m: Vcpkg, options: ...): ScalaNativeConfig (returns custom case class, not affiliated with Scala Native build tooling) with the logic adapted from all the variants above.
  • sbt-vcpkg Provide a VcpkgNativePlugin that automatically configures the project where ScalaNativePlugin is enabled
    I don't think there is a way to provide two plugins in the same module without forcing a Scala Native plugin dependency, but I need to try that.
  • mill-vcpkg Mill is cool and all that and that functionality, I think, can be implemented in the same module because SN support is built-in. @Baccata can you confirm please?

Local vcpkg.json support

If the user has a vcpkg.json in their project, we should parse it and extract dependency list from it.

The dependency list should be merged with whatever is specified in the build tool.

  • core - I don't think there's much we should do in here. I don't want to introduce any json dependency, and all build tools have some ability to read json.
  • sbt-vcpkg - provide a vcpkgJson: Task[String], with ThisBuild / vcpkgJson := (ThisBuild/baseDirectory).value / "vcpkg.json", but also overridable in each project
  • mill-vcpkg - something similar to sbt-vcpkg

Respect VCPKG_ROOT by... ignoring it? 🤯

About 20 days ago, GH runners started settings VCPKG_ROOT variable:
actions/runner-images#6228

This causes basically all of my sbt-vcpkg-based projects to fail.

Through vigorous scientific testing in this PR I've determined that it's indeed caused by the variable and it can be overridden if necessary.

I think the plan should be:

  1. Harden the setting for VcpkgRoot
    • Users should be able to set them manually
    • Users should specify to use the environment variable
    • Users should be able to rely on default cache locations (current behaviour)
    • Users should specify whether they want to allow bootstrapping
    • All the different init mechanisms should come with a orElse method to build a fallback chain
  2. Set the default mode to VcpkgRoot.FromEnv(allowBootstrap = true).orElse(VcpkgRoot.SystemCache(allowBootstrap = true) - "if the env variable is present, use that, and if the vcpkg binary is not there - allow bootstrapping that location. if the variable is not present, use system cache location"

Run example as part of CI on Windows

See #42 for inspiration.
Hopefully, it should be quite simple because of reliance on vcpkg. I make this statement ignoring every shred of my experience of windows.

Integrate with pkg-config

If pkg-config is available, then we should be able to pick up compilation and linking flags from pkg-config, the same way that Gtk
suggests you run gtk examples:

cc `pkg-config --cflags gtk4` hello.c -o hello `pkg-config --libs gtk4`

we need to provide a PKG_CONFIG_PATH pointing at %InstallDir%/<triplet>/lib/pkgconfig/ which will contain all the necessary .pc files

Provide a way to update vcpkg

  1. Pull to latest
  2. Re-bootstrap the script

Without re-bootstrapping, you get

[error] [vcpkg stdout] CMake Error at scripts/cmake/vcpkg_minimum_required.cmake:29 (message):
[error] [vcpkg stdout]   Your vcpkg executable is from 2022-09-20 which is older than required by
[error] [vcpkg stdout]   the caller of vcpkg_minimum_required(VERSION 2022-10-12).  Please
[error] [vcpkg stdout]   re-acquire vcpkg by running bootstrap-vcpkg.
[error] [vcpkg stdout] Call Stack (most recent call first):
[error] [vcpkg stdout]   scripts/ports.cmake:87 (vcpkg_minimum_required)

Static/dynamic linking not configurable

I'm not entirely sure about this, but I think the static/dynamic linking configuration is not working:

I see that there's a staticLinking configuration in

that defaults to false, but it doesn't seem to be used anywhere?

On top of that, I see that in

the default is Linking.Static and I don't see any reference to Linking.Dynamic in the code other than
val lnk = (linking, os) match {
case (Linking.Static, Windows) => Some("static")
case (Linking.Dynamic, Linux | MacOS) => Some("dynamic")
case _ => None
}

So, IIUC, currently on Windows the linking is always static (which matches what I'm seeing) and in Linux/MacOS uses the default?

Handle transitive dependencies

When running something like sn-vcpkg scala-cli libidn2, vcpkg fetchs the libraries and it's dependencies

However, it appears that those are not automatically injected in the --native-compile/--native-linking, so one always needs to specify all transitive dependencies manually.

It would be nice if those were automatically included, which doesn't seem to be the case now.

Rename to sn-vcpkg

In the Welsh tradition, we shall not surrender a single vowel to the English usurpers

Don't re-run `install` if the package is already present

Even though installing packages second time is much faster, it's still unnecessary, as you can invoke list command:

$ vcpkg/vcpkg list --x-install-root ./local-install
czmq:arm64-osx                                     4.2.1#1          High-level C binding for ZeroMQ
libpq:arm64-osx                                    14.1#2           The official database access API of postgresql
libpq[bonjour]:arm64-osx                                            Build with Bonjour support (--with-bonjour)
libpq[lz4]:arm64-osx                                                Use lz4 (else --without-lz4)
libpq[openssl]:arm64-osx                                            support for encrypted client connections and ran...
libpq[zlib]:arm64-osx                                               Use zlib (else --without-zlib)
lz4:arm64-osx                                      1.9.3#3          Lossless compression algorithm, providing compre...
openssl:arm64-osx                                  3.0.3#2          OpenSSL is an open source project that provides ...
vcpkg-cmake-config:arm64-osx                       2022-02-06
vcpkg-cmake:arm64-osx                              2022-05-10
zeromq:arm64-osx                                   4.3.4#5          The ZeroMQ lightweight messaging kernel is a lib...
zlib:arm64-osx                                     1.2.12#1         A compression library

We should add a vcpkgInstalled task to sbt/mill, which would return a list of currently installed dependencies, so that they can be skipped if necessary.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.