diff --git a/.scalafmt.conf b/.scalafmt.conf index 2020e82..47157f6 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -2,9 +2,10 @@ style = defaultWithAlign docstrings = JavaDoc assumeStandardLibraryStripMargin = true project.excludeFilters = [ - "tests/samples/[^/]*[.]scala" + "bindings/[^/]+/src/main/.*[.]scala" "docs/src/test/scala/org/example/.*[.]scala" "sbt-scala-native-bindgen/.*/expected/.*[.]scala" + "tests/samples/[^/]*[.]scala" ] project.git = true runner.dialect = Scala211 diff --git a/Dockerfile b/Dockerfile index 45d74cf..1964782 100644 --- a/Dockerfile +++ b/Dockerfile @@ -10,12 +10,18 @@ RUN set -x \ && apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 2EE0EA64E40A89B84B2DF73499E82A75642AC823 \ && apt update \ && apt install -y --no-install-recommends \ + locales locales-all \ g++ openjdk-8-jdk-headless sbt cmake make curl git \ zlib1g-dev \ libgc-dev libunwind8-dev libre2-dev \ nlohmann-json-dev \ && rm -rf /var/lib/apt/lists/* +ARG LOCALE=en_US.UTF-8 +ENV LANG=$LOCALE +ENV LANGUAGE=$LOCALE +ENV LC_ALL=$LOCALE + ARG LLVM_VERSION=6.0 ENV LLVM_VERSION=$LLVM_VERSION RUN set -x \ @@ -26,4 +32,14 @@ RUN set -x \ && rm -rf /var/lib/apt/lists/* ENV PATH=$PATH:/usr/lib/llvm-$LLVM_VERSION/bin + +##bindings-dev-package +# Install binding dependencies +RUN set -x \ + && apt update \ + && apt install -y --no-install-recommends \ + libutf8proc-dev \ + && rm -rf /var/lib/apt/lists/* +##bindings-dev-package + WORKDIR /src diff --git a/bindings/iconv/src/main/scala/org/scalanative/bindgen/bindings/iconv/iconv.scala b/bindings/iconv/src/main/scala/org/scalanative/bindgen/bindings/iconv/iconv.scala new file mode 100644 index 0000000..d068f0f --- /dev/null +++ b/bindings/iconv/src/main/scala/org/scalanative/bindgen/bindings/iconv/iconv.scala @@ -0,0 +1,16 @@ +package org.scalanative.bindgen.bindings.iconv + +import scala.scalanative._ +import scala.scalanative.native._ + +@native.extern +object iconv { + type iconv_t = native.Ptr[Byte] + def iconv_open(__tocode: native.CString, __fromcode: native.CString): native.Ptr[Byte] = native.extern + def iconv(__cd: native.Ptr[Byte], __inbuf: native.Ptr[native.CString], __inbytesleft: native.Ptr[native.CSize], __outbuf: native.Ptr[native.CString], __outbytesleft: native.Ptr[native.CSize]): native.CSize = native.extern + def iconv_close(__cd: native.Ptr[Byte]): native.CInt = native.extern + + object defines { + val _ICONV_H: native.CInt = 1 + } +} diff --git a/bindings/iconv/src/test/scala/org/scalanative/bindgen/bindings/tests/IconvSpec.scala b/bindings/iconv/src/test/scala/org/scalanative/bindgen/bindings/tests/IconvSpec.scala new file mode 100644 index 0000000..f52ff90 --- /dev/null +++ b/bindings/iconv/src/test/scala/org/scalanative/bindgen/bindings/tests/IconvSpec.scala @@ -0,0 +1,72 @@ +package org.scalanative.bindgen.bindings.iconv.tests + +import org.scalatest.FunSpec + +class IconvSpec extends FunSpec { + describe("iconv") { + it("should convert back and forth between UTF-8 and ISO-8859-1") { + //#usage-example + import org.scalanative.bindgen.bindings.iconv.iconv._ + import scala.scalanative.native._ + import java.nio.charset.Charset + + val UTF8 = Charset.forName("UTF-8") + val encode = iconv_open(c"UTF-8", c"ISO-8859-1") + val decode = iconv_open(c"ISO-8859-1", c"UTF-8") + + Zone { implicit zone => + val originalBuf = toCString("øre", UTF8) // Ear in Danish + val originalBufPtr = alloc[CString] + !originalBufPtr = originalBuf + val originalBytesLeft = alloc[CSize] + !originalBytesLeft = string.strlen(originalBuf) + //#usage-example + assert(!originalBytesLeft == 4) + //#usage-example + + val translatedBuf = alloc[Byte](32) + val translatedBufPtr = alloc[CString] + !translatedBufPtr = translatedBuf + val translatedBytesLeft = alloc[CSize] + !translatedBytesLeft = 32 + + val translatedCode = iconv( + encode, + originalBufPtr, + originalBytesLeft, + translatedBufPtr, + translatedBytesLeft + ) + //#usage-example + + assert(translatedCode == 0) + + !translatedBufPtr = translatedBuf + !translatedBytesLeft = string.strlen(translatedBuf) + + val roundtripBuf = alloc[Byte](32) + val roundtripBufPtr = alloc[CString] + !roundtripBufPtr = roundtripBuf + val roundtripBytesLeft = alloc[CSize] + !roundtripBytesLeft = 32 + + val roundtripCode = iconv( + decode, + translatedBufPtr, + translatedBytesLeft, + roundtripBufPtr, + roundtripBytesLeft + ) + + assert(string.strcmp(originalBuf, roundtripBuf) == 0) + //#usage-example + } + //#usage-example + + //#usage-example + iconv_close(encode) + //#usage-example + iconv_close(decode) + } + } +} diff --git a/bindings/posix/src/main/scala/org/scalanative/bindgen/bindings/posix/fnmatch.scala b/bindings/posix/src/main/scala/org/scalanative/bindgen/bindings/posix/fnmatch.scala new file mode 100644 index 0000000..cce19dd --- /dev/null +++ b/bindings/posix/src/main/scala/org/scalanative/bindgen/bindings/posix/fnmatch.scala @@ -0,0 +1,14 @@ +package org.scalanative.bindgen.bindings.posix + +import scala.scalanative._ +import scala.scalanative.native._ + +@native.extern +object fnmatch { + def fnmatch(__pattern: native.CString, __name: native.CString, __flags: native.CInt): native.CInt = native.extern + + object defines { + val _FNMATCH_H: native.CInt = 1 + val FNM_NOMATCH: native.CInt = 1 + } +} diff --git a/bindings/posix/src/main/scala/org/scalanative/bindgen/bindings/posix/regex.scala b/bindings/posix/src/main/scala/org/scalanative/bindgen/bindings/posix/regex.scala new file mode 100644 index 0000000..4f37582 --- /dev/null +++ b/bindings/posix/src/main/scala/org/scalanative/bindgen/bindings/posix/regex.scala @@ -0,0 +1,59 @@ +package org.scalanative.bindgen.bindings.posix + +import scala.scalanative._ +import scala.scalanative.native._ + +@native.extern +object regex { + type enum_reg_errcode_t = native.CUnsignedInt + object enum_reg_errcode_t { + final val REG_NOERROR: enum_reg_errcode_t = 0.toUInt + final val REG_NOMATCH: enum_reg_errcode_t = 1.toUInt + final val REG_BADPAT: enum_reg_errcode_t = 2.toUInt + final val REG_ECOLLATE: enum_reg_errcode_t = 3.toUInt + final val REG_ECTYPE: enum_reg_errcode_t = 4.toUInt + final val REG_EESCAPE: enum_reg_errcode_t = 5.toUInt + final val REG_ESUBREG: enum_reg_errcode_t = 6.toUInt + final val REG_EBRACK: enum_reg_errcode_t = 7.toUInt + final val REG_EPAREN: enum_reg_errcode_t = 8.toUInt + final val REG_EBRACE: enum_reg_errcode_t = 9.toUInt + final val REG_BADBR: enum_reg_errcode_t = 10.toUInt + final val REG_ERANGE: enum_reg_errcode_t = 11.toUInt + final val REG_ESPACE: enum_reg_errcode_t = 12.toUInt + final val REG_BADRPT: enum_reg_errcode_t = 13.toUInt + final val REG_EEND: enum_reg_errcode_t = 14.toUInt + final val REG_ESIZE: enum_reg_errcode_t = 15.toUInt + final val REG_ERPAREN: enum_reg_errcode_t = 16.toUInt + } + + type s_reg_t = native.CLong + type active_reg_t = native.CUnsignedLong + type reg_syntax_t = native.CUnsignedLong + type reg_errcode_t = enum_reg_errcode_t + type struct_re_pattern_buffer = native.CArray[Byte, native.Nat.Digit[native.Nat._6, native.Nat._4]] + type regex_t = struct_re_pattern_buffer + type regoff_t = native.CInt + type struct_regmatch_t = native.CStruct2[regoff_t, regoff_t] + type regmatch_t = struct_regmatch_t + val re_syntax_options: reg_syntax_t = native.extern + def regcomp(__preg: native.Ptr[regex_t], __pattern: native.CString, __cflags: native.CInt): native.CInt = native.extern + def regexec(__preg: native.Ptr[regex_t], __string: native.CString, __nmatch: native.CSize, __pmatch: native.Ptr[regmatch_t], __eflags: native.CInt): native.CInt = native.extern + def regerror(__errcode: native.CInt, __preg: native.Ptr[regex_t], __errbuf: native.CString, __errbuf_size: native.CSize): native.CSize = native.extern + def regfree(__preg: native.Ptr[regex_t]): Unit = native.extern + + object defines { + val _REGEX_H: native.CInt = 1 + val REG_EXTENDED: native.CInt = 1 + val REG_NOTBOL: native.CInt = 1 + } + + object implicits { + implicit class struct_regmatch_t_ops(val p: native.Ptr[struct_regmatch_t]) extends AnyVal { + def rm_so: regoff_t = !p._1 + def rm_so_=(value: regoff_t): Unit = !p._1 = value + def rm_eo: regoff_t = !p._2 + def rm_eo_=(value: regoff_t): Unit = !p._2 = value + } + def struct_regmatch_t()(implicit z: native.Zone): native.Ptr[struct_regmatch_t] = native.alloc[struct_regmatch_t] + } +} diff --git a/bindings/posix/src/test/scala/org/scalanative/bindgen/bindings/tests/FnmatchSpec.scala b/bindings/posix/src/test/scala/org/scalanative/bindgen/bindings/tests/FnmatchSpec.scala new file mode 100644 index 0000000..e3427a9 --- /dev/null +++ b/bindings/posix/src/test/scala/org/scalanative/bindgen/bindings/tests/FnmatchSpec.scala @@ -0,0 +1,19 @@ +package org.scalanative.bindgen.bindings.tests + +import org.scalatest.FunSpec + +class FnmatchSpec extends FunSpec { + describe("fnmatch") { + it("should match patterns") { + //#usage-example + import scala.scalanative.native._ + import org.scalanative.bindgen.bindings.posix.fnmatch._ + + assert(fnmatch(c"*.md", c"README.md", 0) == 0) + assert(fnmatch(c"*.[ch]", c"main.h", 0) == 0) + assert(fnmatch(c"*.[ch]", c"main.c", 0) == 0) + assert(fnmatch(c"*.md", c"README_md", 0) == defines.FNM_NOMATCH) + //#usage-example + } + } +} diff --git a/bindings/posix/src/test/scala/org/scalanative/bindgen/bindings/tests/RegexSpec.scala b/bindings/posix/src/test/scala/org/scalanative/bindgen/bindings/tests/RegexSpec.scala new file mode 100644 index 0000000..4be4a56 --- /dev/null +++ b/bindings/posix/src/test/scala/org/scalanative/bindgen/bindings/tests/RegexSpec.scala @@ -0,0 +1,27 @@ +package org.scalanative.bindgen.bindings.tests + +import org.scalatest.FunSpec + +class RegexSpec extends FunSpec { + describe("regex") { + it("should match regular expressions") { + //#usage-example + import scala.scalanative.native._ + import org.scalanative.bindgen.bindings.posix.regex._ + + val reg = stackalloc[regex_t] + + val compResult = + regcomp(reg, c"Scala \\(\\(J\\(VM\\|S\\)\\)\\|Native\\)", 0) + assert(compResult == 0) + + assert(regexec(reg, c"Scala JVM", 0, null, 0) == 0) + assert(regexec(reg, c"Scala JS", 0, null, 0) == 0) + assert(regexec(reg, c"Scala Native", 0, null, 0) == 0) + assert(regexec(reg, c"Scala .NET", 0, null, 0) != 0) + + regfree(reg) + //#usage-example + } + } +} diff --git a/bindings/utf8proc/src/main/scala/org/scalanative/bindgen/bindings/utf8proc/utf8proc.scala b/bindings/utf8proc/src/main/scala/org/scalanative/bindgen/bindings/utf8proc/utf8proc.scala new file mode 100644 index 0000000..0ea80aa --- /dev/null +++ b/bindings/utf8proc/src/main/scala/org/scalanative/bindgen/bindings/utf8proc/utf8proc.scala @@ -0,0 +1,193 @@ +package org.scalanative.bindgen.bindings.utf8proc + +import scala.scalanative._ +import scala.scalanative.native._ + +@native.link("utf8proc") +@native.extern +object utf8proc { + type enum_utf8proc_option_t = native.CUnsignedInt + object enum_utf8proc_option_t { + final val UTF8PROC_NULLTERM: enum_utf8proc_option_t = 1.toUInt + final val UTF8PROC_STABLE: enum_utf8proc_option_t = 2.toUInt + final val UTF8PROC_COMPAT: enum_utf8proc_option_t = 4.toUInt + final val UTF8PROC_COMPOSE: enum_utf8proc_option_t = 8.toUInt + final val UTF8PROC_DECOMPOSE: enum_utf8proc_option_t = 16.toUInt + final val UTF8PROC_IGNORE: enum_utf8proc_option_t = 32.toUInt + final val UTF8PROC_REJECTNA: enum_utf8proc_option_t = 64.toUInt + final val UTF8PROC_NLF2LS: enum_utf8proc_option_t = 128.toUInt + final val UTF8PROC_NLF2PS: enum_utf8proc_option_t = 256.toUInt + final val UTF8PROC_NLF2LF: enum_utf8proc_option_t = 384.toUInt + final val UTF8PROC_STRIPCC: enum_utf8proc_option_t = 512.toUInt + final val UTF8PROC_CASEFOLD: enum_utf8proc_option_t = 1024.toUInt + final val UTF8PROC_CHARBOUND: enum_utf8proc_option_t = 2048.toUInt + final val UTF8PROC_LUMP: enum_utf8proc_option_t = 4096.toUInt + final val UTF8PROC_STRIPMARK: enum_utf8proc_option_t = 8192.toUInt + } + + type enum_utf8proc_category_t = native.CUnsignedInt + object enum_utf8proc_category_t { + final val UTF8PROC_CATEGORY_CN: enum_utf8proc_category_t = 0.toUInt + final val UTF8PROC_CATEGORY_LU: enum_utf8proc_category_t = 1.toUInt + final val UTF8PROC_CATEGORY_LL: enum_utf8proc_category_t = 2.toUInt + final val UTF8PROC_CATEGORY_LT: enum_utf8proc_category_t = 3.toUInt + final val UTF8PROC_CATEGORY_LM: enum_utf8proc_category_t = 4.toUInt + final val UTF8PROC_CATEGORY_LO: enum_utf8proc_category_t = 5.toUInt + final val UTF8PROC_CATEGORY_MN: enum_utf8proc_category_t = 6.toUInt + final val UTF8PROC_CATEGORY_MC: enum_utf8proc_category_t = 7.toUInt + final val UTF8PROC_CATEGORY_ME: enum_utf8proc_category_t = 8.toUInt + final val UTF8PROC_CATEGORY_ND: enum_utf8proc_category_t = 9.toUInt + final val UTF8PROC_CATEGORY_NL: enum_utf8proc_category_t = 10.toUInt + final val UTF8PROC_CATEGORY_NO: enum_utf8proc_category_t = 11.toUInt + final val UTF8PROC_CATEGORY_PC: enum_utf8proc_category_t = 12.toUInt + final val UTF8PROC_CATEGORY_PD: enum_utf8proc_category_t = 13.toUInt + final val UTF8PROC_CATEGORY_PS: enum_utf8proc_category_t = 14.toUInt + final val UTF8PROC_CATEGORY_PE: enum_utf8proc_category_t = 15.toUInt + final val UTF8PROC_CATEGORY_PI: enum_utf8proc_category_t = 16.toUInt + final val UTF8PROC_CATEGORY_PF: enum_utf8proc_category_t = 17.toUInt + final val UTF8PROC_CATEGORY_PO: enum_utf8proc_category_t = 18.toUInt + final val UTF8PROC_CATEGORY_SM: enum_utf8proc_category_t = 19.toUInt + final val UTF8PROC_CATEGORY_SC: enum_utf8proc_category_t = 20.toUInt + final val UTF8PROC_CATEGORY_SK: enum_utf8proc_category_t = 21.toUInt + final val UTF8PROC_CATEGORY_SO: enum_utf8proc_category_t = 22.toUInt + final val UTF8PROC_CATEGORY_ZS: enum_utf8proc_category_t = 23.toUInt + final val UTF8PROC_CATEGORY_ZL: enum_utf8proc_category_t = 24.toUInt + final val UTF8PROC_CATEGORY_ZP: enum_utf8proc_category_t = 25.toUInt + final val UTF8PROC_CATEGORY_CC: enum_utf8proc_category_t = 26.toUInt + final val UTF8PROC_CATEGORY_CF: enum_utf8proc_category_t = 27.toUInt + final val UTF8PROC_CATEGORY_CS: enum_utf8proc_category_t = 28.toUInt + final val UTF8PROC_CATEGORY_CO: enum_utf8proc_category_t = 29.toUInt + } + + type enum_utf8proc_bidi_class_t = native.CUnsignedInt + object enum_utf8proc_bidi_class_t { + final val UTF8PROC_BIDI_CLASS_L: enum_utf8proc_bidi_class_t = 1.toUInt + final val UTF8PROC_BIDI_CLASS_LRE: enum_utf8proc_bidi_class_t = 2.toUInt + final val UTF8PROC_BIDI_CLASS_LRO: enum_utf8proc_bidi_class_t = 3.toUInt + final val UTF8PROC_BIDI_CLASS_R: enum_utf8proc_bidi_class_t = 4.toUInt + final val UTF8PROC_BIDI_CLASS_AL: enum_utf8proc_bidi_class_t = 5.toUInt + final val UTF8PROC_BIDI_CLASS_RLE: enum_utf8proc_bidi_class_t = 6.toUInt + final val UTF8PROC_BIDI_CLASS_RLO: enum_utf8proc_bidi_class_t = 7.toUInt + final val UTF8PROC_BIDI_CLASS_PDF: enum_utf8proc_bidi_class_t = 8.toUInt + final val UTF8PROC_BIDI_CLASS_EN: enum_utf8proc_bidi_class_t = 9.toUInt + final val UTF8PROC_BIDI_CLASS_ES: enum_utf8proc_bidi_class_t = 10.toUInt + final val UTF8PROC_BIDI_CLASS_ET: enum_utf8proc_bidi_class_t = 11.toUInt + final val UTF8PROC_BIDI_CLASS_AN: enum_utf8proc_bidi_class_t = 12.toUInt + final val UTF8PROC_BIDI_CLASS_CS: enum_utf8proc_bidi_class_t = 13.toUInt + final val UTF8PROC_BIDI_CLASS_NSM: enum_utf8proc_bidi_class_t = 14.toUInt + final val UTF8PROC_BIDI_CLASS_BN: enum_utf8proc_bidi_class_t = 15.toUInt + final val UTF8PROC_BIDI_CLASS_B: enum_utf8proc_bidi_class_t = 16.toUInt + final val UTF8PROC_BIDI_CLASS_S: enum_utf8proc_bidi_class_t = 17.toUInt + final val UTF8PROC_BIDI_CLASS_WS: enum_utf8proc_bidi_class_t = 18.toUInt + final val UTF8PROC_BIDI_CLASS_ON: enum_utf8proc_bidi_class_t = 19.toUInt + final val UTF8PROC_BIDI_CLASS_LRI: enum_utf8proc_bidi_class_t = 20.toUInt + final val UTF8PROC_BIDI_CLASS_RLI: enum_utf8proc_bidi_class_t = 21.toUInt + final val UTF8PROC_BIDI_CLASS_FSI: enum_utf8proc_bidi_class_t = 22.toUInt + final val UTF8PROC_BIDI_CLASS_PDI: enum_utf8proc_bidi_class_t = 23.toUInt + } + + type enum_utf8proc_decomp_type_t = native.CUnsignedInt + object enum_utf8proc_decomp_type_t { + final val UTF8PROC_DECOMP_TYPE_FONT: enum_utf8proc_decomp_type_t = 1.toUInt + final val UTF8PROC_DECOMP_TYPE_NOBREAK: enum_utf8proc_decomp_type_t = 2.toUInt + final val UTF8PROC_DECOMP_TYPE_INITIAL: enum_utf8proc_decomp_type_t = 3.toUInt + final val UTF8PROC_DECOMP_TYPE_MEDIAL: enum_utf8proc_decomp_type_t = 4.toUInt + final val UTF8PROC_DECOMP_TYPE_FINAL: enum_utf8proc_decomp_type_t = 5.toUInt + final val UTF8PROC_DECOMP_TYPE_ISOLATED: enum_utf8proc_decomp_type_t = 6.toUInt + final val UTF8PROC_DECOMP_TYPE_CIRCLE: enum_utf8proc_decomp_type_t = 7.toUInt + final val UTF8PROC_DECOMP_TYPE_SUPER: enum_utf8proc_decomp_type_t = 8.toUInt + final val UTF8PROC_DECOMP_TYPE_SUB: enum_utf8proc_decomp_type_t = 9.toUInt + final val UTF8PROC_DECOMP_TYPE_VERTICAL: enum_utf8proc_decomp_type_t = 10.toUInt + final val UTF8PROC_DECOMP_TYPE_WIDE: enum_utf8proc_decomp_type_t = 11.toUInt + final val UTF8PROC_DECOMP_TYPE_NARROW: enum_utf8proc_decomp_type_t = 12.toUInt + final val UTF8PROC_DECOMP_TYPE_SMALL: enum_utf8proc_decomp_type_t = 13.toUInt + final val UTF8PROC_DECOMP_TYPE_SQUARE: enum_utf8proc_decomp_type_t = 14.toUInt + final val UTF8PROC_DECOMP_TYPE_FRACTION: enum_utf8proc_decomp_type_t = 15.toUInt + final val UTF8PROC_DECOMP_TYPE_COMPAT: enum_utf8proc_decomp_type_t = 16.toUInt + } + + type enum_utf8proc_boundclass_t = native.CUnsignedInt + object enum_utf8proc_boundclass_t { + final val UTF8PROC_BOUNDCLASS_START: enum_utf8proc_boundclass_t = 0.toUInt + final val UTF8PROC_BOUNDCLASS_OTHER: enum_utf8proc_boundclass_t = 1.toUInt + final val UTF8PROC_BOUNDCLASS_CR: enum_utf8proc_boundclass_t = 2.toUInt + final val UTF8PROC_BOUNDCLASS_LF: enum_utf8proc_boundclass_t = 3.toUInt + final val UTF8PROC_BOUNDCLASS_CONTROL: enum_utf8proc_boundclass_t = 4.toUInt + final val UTF8PROC_BOUNDCLASS_EXTEND: enum_utf8proc_boundclass_t = 5.toUInt + final val UTF8PROC_BOUNDCLASS_L: enum_utf8proc_boundclass_t = 6.toUInt + final val UTF8PROC_BOUNDCLASS_V: enum_utf8proc_boundclass_t = 7.toUInt + final val UTF8PROC_BOUNDCLASS_T: enum_utf8proc_boundclass_t = 8.toUInt + final val UTF8PROC_BOUNDCLASS_LV: enum_utf8proc_boundclass_t = 9.toUInt + final val UTF8PROC_BOUNDCLASS_LVT: enum_utf8proc_boundclass_t = 10.toUInt + final val UTF8PROC_BOUNDCLASS_REGIONAL_INDICATOR: enum_utf8proc_boundclass_t = 11.toUInt + final val UTF8PROC_BOUNDCLASS_SPACINGMARK: enum_utf8proc_boundclass_t = 12.toUInt + final val UTF8PROC_BOUNDCLASS_PREPEND: enum_utf8proc_boundclass_t = 13.toUInt + final val UTF8PROC_BOUNDCLASS_ZWJ: enum_utf8proc_boundclass_t = 14.toUInt + final val UTF8PROC_BOUNDCLASS_E_BASE: enum_utf8proc_boundclass_t = 15.toUInt + final val UTF8PROC_BOUNDCLASS_E_MODIFIER: enum_utf8proc_boundclass_t = 16.toUInt + final val UTF8PROC_BOUNDCLASS_GLUE_AFTER_ZWJ: enum_utf8proc_boundclass_t = 17.toUInt + final val UTF8PROC_BOUNDCLASS_E_BASE_GAZ: enum_utf8proc_boundclass_t = 18.toUInt + } + + type int8_t = native.CSignedChar + type int16_t = native.CShort + type int32_t = native.CInt + type uint8_t = native.CUnsignedChar + type uint16_t = native.CUnsignedShort + type uint32_t = native.CUnsignedInt + type utf8proc_int8_t = int8_t + type utf8proc_uint8_t = uint8_t + type utf8proc_int16_t = int16_t + type utf8proc_uint16_t = uint16_t + type utf8proc_int32_t = int32_t + type utf8proc_uint32_t = uint32_t + type utf8proc_size_t = native.CSize + type utf8proc_ssize_t = native.CPtrDiff + type utf8proc_bool = native.CBool + type utf8proc_option_t = enum_utf8proc_option_t + type utf8proc_propval_t = utf8proc_int16_t + type struct_utf8proc_property_struct = native.CArray[Byte, native.Nat.Digit[native.Nat._2, native.Nat._4]] + type utf8proc_property_t = struct_utf8proc_property_struct + type utf8proc_category_t = enum_utf8proc_category_t + type utf8proc_bidi_class_t = enum_utf8proc_bidi_class_t + type utf8proc_decomp_type_t = enum_utf8proc_decomp_type_t + type utf8proc_boundclass_t = enum_utf8proc_boundclass_t + type utf8proc_custom_func = native.CFunctionPtr2[utf8proc_int32_t, native.Ptr[Byte], utf8proc_int32_t] + val utf8proc_utf8class: native.CArray[utf8proc_int8_t, native.Nat.Digit[native.Nat._2, native.Nat.Digit[native.Nat._5, native.Nat._6]]] = native.extern + def utf8proc_version(): native.CString = native.extern + def utf8proc_errmsg(errcode: utf8proc_ssize_t): native.CString = native.extern + def utf8proc_iterate(str: native.Ptr[utf8proc_uint8_t], strlen: utf8proc_ssize_t, codepoint_ref: native.Ptr[utf8proc_int32_t]): utf8proc_ssize_t = native.extern + def utf8proc_codepoint_valid(codepoint: utf8proc_int32_t): utf8proc_bool = native.extern + def utf8proc_encode_char(codepoint: utf8proc_int32_t, dst: native.Ptr[utf8proc_uint8_t]): utf8proc_ssize_t = native.extern + def utf8proc_get_property(codepoint: utf8proc_int32_t): native.Ptr[utf8proc_property_t] = native.extern + def utf8proc_decompose_char(codepoint: utf8proc_int32_t, dst: native.Ptr[utf8proc_int32_t], bufsize: utf8proc_ssize_t, options: utf8proc_option_t, last_boundclass: native.Ptr[native.CInt]): utf8proc_ssize_t = native.extern + def utf8proc_decompose(str: native.Ptr[utf8proc_uint8_t], strlen: utf8proc_ssize_t, buffer: native.Ptr[utf8proc_int32_t], bufsize: utf8proc_ssize_t, options: utf8proc_option_t): utf8proc_ssize_t = native.extern + def utf8proc_decompose_custom(str: native.Ptr[utf8proc_uint8_t], strlen: utf8proc_ssize_t, buffer: native.Ptr[utf8proc_int32_t], bufsize: utf8proc_ssize_t, options: utf8proc_option_t, custom_func: native.CFunctionPtr2[utf8proc_int32_t, native.Ptr[Byte], utf8proc_int32_t], custom_data: native.Ptr[Byte]): utf8proc_ssize_t = native.extern + def utf8proc_normalize_utf32(buffer: native.Ptr[utf8proc_int32_t], length: utf8proc_ssize_t, options: utf8proc_option_t): utf8proc_ssize_t = native.extern + def utf8proc_reencode(buffer: native.Ptr[utf8proc_int32_t], length: utf8proc_ssize_t, options: utf8proc_option_t): utf8proc_ssize_t = native.extern + def utf8proc_grapheme_break_stateful(codepoint1: utf8proc_int32_t, codepoint2: utf8proc_int32_t, state: native.Ptr[utf8proc_int32_t]): utf8proc_bool = native.extern + def utf8proc_grapheme_break(codepoint1: utf8proc_int32_t, codepoint2: utf8proc_int32_t): utf8proc_bool = native.extern + def utf8proc_tolower(c: utf8proc_int32_t): utf8proc_int32_t = native.extern + def utf8proc_toupper(c: utf8proc_int32_t): utf8proc_int32_t = native.extern + def utf8proc_totitle(c: utf8proc_int32_t): utf8proc_int32_t = native.extern + def utf8proc_charwidth(codepoint: utf8proc_int32_t): native.CInt = native.extern + def utf8proc_category(codepoint: utf8proc_int32_t): utf8proc_category_t = native.extern + def utf8proc_category_string(codepoint: utf8proc_int32_t): native.CString = native.extern + def utf8proc_map(str: native.Ptr[utf8proc_uint8_t], strlen: utf8proc_ssize_t, dstptr: native.Ptr[native.Ptr[utf8proc_uint8_t]], options: utf8proc_option_t): utf8proc_ssize_t = native.extern + def utf8proc_map_custom(str: native.Ptr[utf8proc_uint8_t], strlen: utf8proc_ssize_t, dstptr: native.Ptr[native.Ptr[utf8proc_uint8_t]], options: utf8proc_option_t, custom_func: native.CFunctionPtr2[utf8proc_int32_t, native.Ptr[Byte], utf8proc_int32_t], custom_data: native.Ptr[Byte]): utf8proc_ssize_t = native.extern + def utf8proc_NFD(str: native.Ptr[utf8proc_uint8_t]): native.Ptr[utf8proc_uint8_t] = native.extern + def utf8proc_NFC(str: native.Ptr[utf8proc_uint8_t]): native.Ptr[utf8proc_uint8_t] = native.extern + def utf8proc_NFKD(str: native.Ptr[utf8proc_uint8_t]): native.Ptr[utf8proc_uint8_t] = native.extern + def utf8proc_NFKC(str: native.Ptr[utf8proc_uint8_t]): native.Ptr[utf8proc_uint8_t] = native.extern + + object defines { + val UTF8PROC_VERSION_MAJOR: native.CInt = 2 + val UTF8PROC_VERSION_MINOR: native.CInt = 1 + val UTF8PROC_VERSION_PATCH: native.CInt = 0 + val UTF8PROC_ERROR_NOMEM: native.CInt = -1 + val UTF8PROC_ERROR_OVERFLOW: native.CInt = -2 + val UTF8PROC_ERROR_INVALIDUTF8: native.CInt = -3 + val UTF8PROC_ERROR_NOTASSIGNED: native.CInt = -4 + val UTF8PROC_ERROR_INVALIDOPTS: native.CInt = -5 + } +} diff --git a/bindings/utf8proc/src/test/scala/org/scalanative/bindgen/bindings/tests/Utf8procSpec.scala b/bindings/utf8proc/src/test/scala/org/scalanative/bindgen/bindings/tests/Utf8procSpec.scala new file mode 100644 index 0000000..8700de4 --- /dev/null +++ b/bindings/utf8proc/src/test/scala/org/scalanative/bindgen/bindings/tests/Utf8procSpec.scala @@ -0,0 +1,45 @@ +package org.scalanative.bindgen.bindings.tests + +import org.scalatest.FunSpec + +class Utf8procSpec extends FunSpec { + describe("utf8proc") { + it("should iterate UTF-8 and count character width") { + //#usage-example + import org.scalanative.bindgen.bindings.utf8proc.utf8proc._ + import scala.scalanative.native._ + + val text = c"Spørge" + val textlen = string.strlen(text) + + val codepoint = stackalloc[utf8proc_int32_t] + var textpos: CSize = 0 + var textwidth: CSize = 0 + + while (textpos < textlen) { + val bytes = utf8proc_iterate( + text.cast[Ptr[UByte]] + textpos, + textlen - textpos, + codepoint + ) + textwidth += utf8proc_charwidth(!codepoint) + textpos += bytes + } + + assert(textlen == 7) + assert(textwidth == 6) + //#usage-example + } + + it("utf8proc_tolower") { + import org.scalanative.bindgen.bindings.utf8proc.utf8proc._ + + val `Ø` = 0x00D8 + val `ø` = 0x00F8 + val `😱` = 0x1F631 + + assert(utf8proc_tolower(`Ø`) == `ø`) + assert(utf8proc_tolower(`😱`) == `😱`) + } + } +} diff --git a/build.sbt b/build.sbt index d9e84d8..18f350b 100644 --- a/build.sbt +++ b/build.sbt @@ -1,8 +1,9 @@ import scala.sys.process._ +import scala.util.Try import org.scalanative.bindgen.sbt.ScalaNativeBindgenPlugin +import BindingHelpers._ -addCommandAlias("verify", - "; tests/test ; docs/test ; ^scripted ; docs/makeSite") +addCommandAlias("verify", "; test ; ^scripted ; docs/makeSite") val Versions = new { val scala210 = "2.10.6" @@ -25,6 +26,7 @@ inThisBuild( "-encoding", "utf8" ), + parallelExecution in Global := false, scmInfo := Some( ScmInfo(url("https://github.com/kornilova-l/scala-native-bindgen"), "scm:git:git@github.com:kornilova-l/scala-native-bindgen.git")), @@ -51,6 +53,7 @@ val root = project("scala-native-bindgen") samples, tools, sbtPlugin, + bindings, docs ) .enablePlugins(ReleasePlugin) @@ -60,6 +63,10 @@ val root = project("scala-native-bindgen") releaseVersionFile := target.value / "unused-version.sbt", releaseProcess := { import ReleaseTransformations._ + + val setReleaseVersions: String => State => State = + v => _.put(ReleaseKeys.versions, (v, v)) + Seq[ReleaseStep]( checkSnapshotDependencies, setReleaseVersions(version.value), @@ -98,7 +105,7 @@ lazy val samples = project("samples") .settings( publish / skip := true, scalaVersion := Versions.scala211, - libraryDependencies += "com.lihaoyi" %%% "utest" % "0.6.3" % "test", + libraryDependencies += "com.lihaoyi" %%% "utest" % "0.6.3" % Test, testFrameworks += new TestFramework("utest.runner.Framework"), nativeLinkStubs := true, compileTask("bindgentests", baseDirectory) @@ -133,8 +140,6 @@ lazy val docs = project("docs") .settings( publish / skip := true, scalaVersion := Versions.scala211, - // FIXME: Remove when a version has been released with Test scope settings. - ScalaNativeBindgenPlugin.nativeBindgenScopedSettings(Test), Test / nativeBindings += { NativeBinding((Test / resourceDirectory).value / "vector.h") .name("vector") @@ -159,13 +164,43 @@ lazy val docs = project("docs") } ) +lazy val bindings = project("bindings") + .settings( + publish / skip := false + ) + .aggregate( + libiconv, + libposix, + libutf8proc + ) + +lazy val libiconv = bindingProject("iconv") + .configure(binding("iconv.h")) + .settings( + Test / nativeLinkingOptions ++= { + // Link with libiconv on macOS. + Option(System.getProperty("os.name")) match { + case Some("Mac OS X") => Seq("-liconv") + case _ => Seq.empty + } + } + ) + +//#sbt-binding-project +lazy val libposix = bindingProject("posix") + .configure(binding("fnmatch.h")) + .configure(binding("regex.h")) +//#sbt-binding-project + +lazy val libutf8proc = bindingProject("utf8proc") + .configure(binding("utf8proc.h", Some("utf8proc"))) + def project(name: String, plugged: AutoPlugin*) = { val unplugged = Seq(ScriptedPlugin).filterNot(plugged.toSet) Project(id = name, base = file(name)) .disablePlugins(unplugged: _*) - .enablePlugins(GitPlugin) - .enablePlugins(GitVersioning) + .enablePlugins(GitPlugin, GitVersioning) .settings( versionWithGit, git.useGitDescribe := true, @@ -187,9 +222,6 @@ def project(name: String, plugged: AutoPlugin*) = { ) } -lazy val setReleaseVersions: String => State => State = - v => _.put(ReleaseKeys.versions, (v, v)) - def compileTask(libname: String, srcDirTask: SettingKey[File]) = Def.settings( Test / nativeLinkingOptions += { Seq("-L", (Test / target).value.getAbsoluteFile / "bindgen").mkString @@ -239,3 +271,55 @@ def compileTask(libname: String, srcDirTask: SettingKey[File]) = Def.settings( (Test / compile).value } ) + +// Add Clang's directory include dir with platform specific headers, like stddef.h. +lazy val bindingsExtraArgs = Try { + val version = "llvm-config --version".!!.trim + val libDir = "llvm-config --libdir".!!.trim + s"-I$libDir/clang/$version/include" +}.toOption + +def bindingProject(name: String) = { + project(s"lib$name") + .enablePlugins(ScalaNativePlugin, ScalaNativeBindgenPlugin) + .in(file(s"bindings/$name")) + .settings( + scalaVersion := Versions.scala211, + nativeLinkStubs := true, + libraryDependencies += "org.scalatest" %%% "scalatest" % "3.2.0-SNAP10" % Test, + Compile / nativeBindgen / target := + (Compile / scalaSource).value / "org/scalanative/bindgen/bindings" / name + ) +} + +def binding(header: String, link: Option[String] = None)( + project: Project): Project = { + val headerFile = file("/usr/include") / header + val libname = project.base.getName + project.settings( + inConfig(Compile)( + Def.settings( + nativeBindings ++= { + if (headerFile.exists) Seq { + NativeBinding(headerFile) + .name(header.replace(".h", "")) + .packageName(s"org.scalanative.bindgen.bindings.$libname") + .maybe(link, _.link) + .excludePrefix("__") + .extraArgs(bindingsExtraArgs.toSeq: _*) + .extraArgs("-D_POSIX_C_SOURCE") + } else { + Seq.empty + } + } + )), + test := (Def.taskDyn { + if (headerFile.exists) + Def.task { (Test / test).value } else + Def.task { + streams.value.log.warn( + s"Skipping $libname tests due to missing header file $headerFile") + } + }).value + ) +} diff --git a/docs/src/paradox/bindings/iconv.md b/docs/src/paradox/bindings/iconv.md new file mode 100644 index 0000000..f2603bf --- /dev/null +++ b/docs/src/paradox/bindings/iconv.md @@ -0,0 +1,17 @@ +# Iconv - Character set conversion + +To use this binding add the following dependency: + +@@dependency[sbt,Maven,Gradle] { + group="org.scala-native.bindgen" + artifact="libposix_$scala.binary.version$" + version="$project.version$" +} + +The [`iconv.h`] header allows to convert text between different character sets, for example UTF-8 to ISO-8859-1. + +## Example + +@@snip [iconv](../../../../bindings/iconv/src/test/scala/org/scalanative/bindgen/bindings/tests/IconvSpec.scala) { #usage-example } + + [`iconv.h`]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/iconv.h.html diff --git a/docs/src/paradox/bindings/index.md b/docs/src/paradox/bindings/index.md new file mode 100644 index 0000000..0c390e3 --- /dev/null +++ b/docs/src/paradox/bindings/index.md @@ -0,0 +1,13 @@ +# Bindings + +The following bindings have been generated with bindgen. + +@@ toc { depth=1 } + +@@@ index + +* [posix](posix.md) +* [iconv](iconv.md) +* [utf8proc](utf8proc.md) + +@@@ \ No newline at end of file diff --git a/docs/src/paradox/bindings/posix.md b/docs/src/paradox/bindings/posix.md new file mode 100644 index 0000000..c16a633 --- /dev/null +++ b/docs/src/paradox/bindings/posix.md @@ -0,0 +1,29 @@ +# POSIX + +An addition to Scala Native's [POSIX](http://www.scala-native.org/en/latest/lib/posixlib.html) bindings. To use one of the POSIX bindings you must add it as a dependency: + +@@dependency[sbt,Maven,Gradle] { + group="org.scala-native.bindgen" + artifact="libposix_$scala.binary.version$" + version="$project.version$" +} + +Binding objects are available under the package name ` + +| Header | Description +|----------------------|------------------------------------------------------| +| [`fnmatch.h`] | Check if a file or path name matches a shell pattern +| [`regex.h`] | Regular expression library + + [`fnmatch.h`]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/fnmatch.h.html + [`regex.h`]: http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/regex.h.html + +## Examples + +Using `fnmatch.h`: + +@@snip [fnmatch](../../../../bindings/posix/src/test/scala/org/scalanative/bindgen/bindings/tests/FnmatchSpec.scala) { #usage-example } + +Using `regex.h`: + +@@snip [regex](../../../../bindings/posix/src/test/scala/org/scalanative/bindgen/bindings/tests/RegexSpec.scala) { #usage-example } diff --git a/docs/src/paradox/bindings/utf8proc.md b/docs/src/paradox/bindings/utf8proc.md new file mode 100644 index 0000000..27a482e --- /dev/null +++ b/docs/src/paradox/bindings/utf8proc.md @@ -0,0 +1,17 @@ +# Utf8proc - UTF-8 text processing + +This binding for [`utf8proc.h`] provides Unicode normalization, case-folding, and other operations for strings in the UTF-8 encoding. + +To use it add the following dependency: + +@@dependency[sbt,Maven,Gradle] { + group="org.scala-native.bindgen" + artifact="libutf8proc_$scala.binary.version$" + version="$project.version$" +} + +## Example + +@@snip [iconv](../../../../bindings/utf8proc/src/test/scala/org/scalanative/bindgen/bindings/tests/Utf8procSpec.scala) { #usage-example } + + [`utf8proc.h`]: https://juliastrings.github.io/utf8proc/doc/ \ No newline at end of file diff --git a/docs/src/paradox/contrib/bindings.md b/docs/src/paradox/contrib/bindings.md new file mode 100644 index 0000000..53ee8ff --- /dev/null +++ b/docs/src/paradox/contrib/bindings.md @@ -0,0 +1,49 @@ +# Contributing Bindings + +## Adding a new Bindings + +To add a new binding add a new project in `build.sbt` with the name of the artifact as well as a binding configuration for each header file and optionally the library to link with. The following example shows how it is possible to generate multiple bindings per project. For most libraries a single binding should be sufficient. + +@@snip [build.sbt](../../../../build.sbt) { #sbt-binding-project } + +The new sbt project should also be added to the `bindings` project's list of aggregated projects. + +Optionally update the top-level `Dockerfile` to install the binding library's `-dev` package. + +@@snip [Dockerfile](../../../../Dockerfile) { #bindings-dev-package } + +Remember to rebuild the development docker image if you change the `Dockerfile`. + +```sh +docker-compose build ubuntu-18.04-llvm-6.0 +``` + +Next, run `nativeBindgen` to generate the bindings. Note, to ensure consistency the bindings should be generated in the Linux docker environment. +This can be done by running: + +```sh +docker-compose run --rm ubuntu-18.04-llvm-6.0 sbt bindings/$BINDING/nativeBindgen +``` + +Then write tests for the generated bindings. The test class should be in the `org.scalanative.bindgen.bindings.tests` package to make it easier to write examples for the binding documentation. Verify that the tests pass: + +```sh +docker-compose run --rm ubuntu-18.04-llvm-6.0 sbt bindings/$BINDING/test +``` + +Finally, add a page in the `bindings` folder and document the binding, ideally with an example or two of how to use it. + +## Update all Bindings + +To update the bindings, build the Linux docker environment and run `bindings/nativeBindgen`: + +```sh +docker-compose build ubuntu-18.04-llvm-6.0 +docker-compose run --rm ubuntu-18.04-llvm-6.0 sbt bindings/nativeBindgen +``` + +Run the tests afterwards to verify that everything works: + +```sh +docker-compose run --rm ubuntu-18.04-llvm-6.0 sbt bindings/test +``` diff --git a/docs/src/paradox/contrib/index.md b/docs/src/paradox/contrib/index.md index 68c27c7..094ba0c 100644 --- a/docs/src/paradox/contrib/index.md +++ b/docs/src/paradox/contrib/index.md @@ -10,6 +10,7 @@ information about how to build and contribute to the project. * [guidelines](guidelines.md) * [cmake](cmake.md) * [docker-compose](docker-compose.md) +* [bindings](bindings.md) * [releasing](releasing.md) @@@ diff --git a/docs/src/paradox/index.md b/docs/src/paradox/index.md index 519160b..a5c5212 100644 --- a/docs/src/paradox/index.md +++ b/docs/src/paradox/index.md @@ -32,6 +32,7 @@ This project is distributed under the Scala license. * [Using Generated Bindings](using-generated-bindings.md) * [Integrating Bindings](integrating-bindings.md) * [Limitations](limitations.md) +* [bindings](bindings/index.md) * [Contributor's Guide](contrib/index.md) @@@ diff --git a/docs/src/test/scala/org/example/vector.scala b/docs/src/test/scala/org/example/vector.scala index 14743dd..dd25377 100644 --- a/docs/src/test/scala/org/example/vector.scala +++ b/docs/src/test/scala/org/example/vector.scala @@ -9,27 +9,22 @@ object vector { type struct_point = native.CStruct2[native.CFloat, native.CFloat] type struct_vector = native.CStruct2[struct_point, struct_point] def add(v1: native.Ptr[struct_vector], v2: native.Ptr[struct_vector]): native.Ptr[struct_vector] = native.extern -} - -import vector._ -object vectorHelpers { - - implicit class struct_point_ops(val p: native.Ptr[struct_point]) extends AnyVal { - def x: native.CFloat = !p._1 - def x_=(value: native.CFloat): Unit = !p._1 = value - def y: native.CFloat = !p._2 - def y_=(value: native.CFloat): Unit = !p._2 = value + object implicits { + implicit class struct_point_ops(val p: native.Ptr[struct_point]) extends AnyVal { + def x: native.CFloat = !p._1 + def x_=(value: native.CFloat): Unit = !p._1 = value + def y: native.CFloat = !p._2 + def y_=(value: native.CFloat): Unit = !p._2 = value + } + def struct_point()(implicit z: native.Zone): native.Ptr[struct_point] = native.alloc[struct_point] + + implicit class struct_vector_ops(val p: native.Ptr[struct_vector]) extends AnyVal { + def a: native.Ptr[struct_point] = p._1 + def a_=(value: native.Ptr[struct_point]): Unit = !p._1 = !value + def b: native.Ptr[struct_point] = p._2 + def b_=(value: native.Ptr[struct_point]): Unit = !p._2 = !value + } + def struct_vector()(implicit z: native.Zone): native.Ptr[struct_vector] = native.alloc[struct_vector] } - - def struct_point()(implicit z: native.Zone): native.Ptr[struct_point] = native.alloc[struct_point] - - implicit class struct_vector_ops(val p: native.Ptr[struct_vector]) extends AnyVal { - def a: native.Ptr[struct_point] = p._1 - def a_=(value: native.Ptr[struct_point]): Unit = !p._1 = !value - def b: native.Ptr[struct_point] = p._2 - def b_=(value: native.Ptr[struct_point]): Unit = !p._2 = !value - } - - def struct_vector()(implicit z: native.Zone): native.Ptr[struct_vector] = native.alloc[struct_vector] } diff --git a/docs/src/test/scala/org/scalanative/bindgen/docs/VectorSpec.scala b/docs/src/test/scala/org/scalanative/bindgen/docs/VectorSpec.scala index 17d08bc..282c6f2 100644 --- a/docs/src/test/scala/org/scalanative/bindgen/docs/VectorSpec.scala +++ b/docs/src/test/scala/org/scalanative/bindgen/docs/VectorSpec.scala @@ -8,7 +8,7 @@ class VectorSpec extends FunSpec { //#step-1 import scala.scalanative.native.Zone import org.example.vector - import org.example.vectorHelpers._ + import org.example.vector.implicits._ Zone { implicit zone => val vec1p1 = struct_point() diff --git a/project/BindingHelpers.scala b/project/BindingHelpers.scala new file mode 100644 index 0000000..3e9b2f6 --- /dev/null +++ b/project/BindingHelpers.scala @@ -0,0 +1,13 @@ +import org.scalanative.bindgen.BindingOptions + +object BindingHelpers { + implicit class BindingOptionsOps(val options: BindingOptions) extends AnyVal { + type F[T] = BindingOptions => T => BindingOptions + + def maybe[T](opt: Option[T], f: F[T]): BindingOptions = + opt match { + case None => options + case Some(value) => f(options)(value) + } + } +} diff --git a/project/plugins.sbt b/project/plugins.sbt index 29189f8..e0bce4a 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -9,11 +9,11 @@ addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.9.0") libraryDependencies += "org.scala-sbt" %% "scripted-plugin" % sbtVersion.value -val VERSION = "0.3.0-RC0" +val VERSION = "0.3.0-RC1" //#sbt-plugin-example addSbtPlugin("org.scala-native.bindgen" % "sbt-scala-native-bindgen" % VERSION) resolvers += Resolver.bintrayIvyRepo("scala-native-bindgen", "sbt-plugins") resolvers += Resolver.bintrayRepo("scala-native-bindgen", "maven") -//#sbt-plugin-example \ No newline at end of file +//#sbt-plugin-example