Skip to content

Commit 17d7c89

Browse files
authored
Switch to BinaryProvider (#24)
Use GNU libiconv everywhere a usable iconv cannot be found. In particular, this means we no longer use win-iconv on Windows, which allows relying on a more consistent behavior across platforms.
1 parent f0ecb57 commit 17d7c89

File tree

6 files changed

+119
-39
lines changed

6 files changed

+119
-39
lines changed

.travis.yml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,8 @@ os:
44
- linux
55
- osx
66
julia:
7-
- 0.5
87
- 0.6
8+
- 0.7
99
- nightly
1010
notifications:
1111
email: false

README.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
[![Coveralls Coverage Status](https://coveralls.io/repos/nalimilan/StringEncodings.jl/badge.svg?branch=master&service=github)](https://coveralls.io/github/nalimilan/StringEncodings.jl?branch=master)
66
[![Codecov Coverage Status](http://codecov.io/github/nalimilan/StringEncodings.jl/coverage.svg?branch=master)](http://codecov.io/github/nalimilan/StringEncodings.jl?branch=master)
77

8-
[![Julia 0.5 Status](http://pkg.julialang.org/badges/StringEncodings_0.5.svg)](http://pkg.julialang.org/?pkg=StringEncodings&ver=0.5)
98
[![Julia 0.6 Status](http://pkg.julialang.org/badges/StringEncodings_0.6.svg)](http://pkg.julialang.org/?pkg=StringEncodings&ver=0.6)
9+
[![Julia 0.7 Status](http://pkg.julialang.org/badges/StringEncodings_0.7.svg)](http://pkg.julialang.org/?pkg=StringEncodings&ver=0.7)
1010

11-
This Julia package provides support for decoding and encoding texts between multiple character encodings. It is currently based on the iconv interface, and supports all major platforms (on Windows, it uses the native OS API via [win_iconv](https://github.com/win-iconv/win-iconv/)). In the future, native Julia support for major encodings will be added.
11+
This Julia package provides support for decoding and encoding texts between multiple character encodings. It is currently based on the iconv interface, and supports all major platforms using either the native iconv support or [GNU libiconv](https://www.gnu.org/software/libiconv/). In the future, native Julia support for major encodings will be added.
1212

1313
## Encoding and Decoding Strings
1414
*Encoding* a refers to the process of converting a string (of any `AbstractString` type) to a sequence of bytes represented as a `Vector{UInt8}`. *Decoding* refers to the inverse process.

REQUIRE

+2-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
julia 0.5
2-
BinDeps
1+
julia 0.6
2+
BinaryProvider 0.3.0
33
Compat 0.17.0
4-
@windows WinRPM
54
LegacyStrings 0.1.1

appveyor.yml

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
environment:
22
matrix:
3-
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.5/julia-0.5-latest-win32.exe"
4-
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.5/julia-0.5-latest-win64.exe"
53
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.6/julia-0.6-latest-win32.exe"
64
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.6/julia-0.6-latest-win64.exe"
5+
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x86/0.7/julia-0.7-latest-win32.exe"
6+
- JULIA_URL: "https://julialang-s3.julialang.org/bin/winnt/x64/0.7/julia-0.7-latest-win64.exe"
77
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x86/julia-latest-win32.exe"
88
- JULIA_URL: "https://julialangnightlies-s3.julialang.org/bin/winnt/x64/julia-latest-win64.exe"
99

deps/build.jl

+93-23
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,15 @@
1-
using BinDeps
2-
3-
@BinDeps.setup
4-
51
# Check for an iconv implementation with the GNU (non-POSIX) behavior:
62
# EILSEQ is returned when a sequence cannot be converted to target encoding,
73
# instead of succeeding and only returning the number of invalid conversions
84
# This non-standard behavior is required to allow replacing invalid sequences
95
# with a user-defined character.
106
# Implementations with this behavior include glibc, GNU libiconv (on which Mac
117
# OS X's is based) and win_iconv.
12-
function validate_iconv(n, h)
8+
function validate_iconv(lib, iconv_open, iconv_close, iconv)
9+
h = Libdl.dlopen_e(lib)
10+
h == C_NULL && return false
1311
# Needed to check libc
14-
f = Libdl.dlsym_e(h, "iconv_open")
12+
f = Libdl.dlsym_e(h, iconv_open)
1513
f == C_NULL && return false
1614

1715
cd = ccall(f, Ptr{Void}, (Cstring, Cstring), "ASCII", "UTF-8")
@@ -23,31 +21,103 @@ function validate_iconv(n, h)
2321
inbytesleft = Ref{Csize_t}(sizeof(s))
2422
outbufptr = Ref{Ptr{UInt8}}(pointer(a))
2523
outbytesleft = Ref{Csize_t}(length(a))
26-
ret = ccall(Libdl.dlsym_e(h, "iconv"), Csize_t,
24+
ret = ccall(Libdl.dlsym_e(h, iconv), Csize_t,
2725
(Ptr{Void}, Ptr{Ptr{UInt8}}, Ref{Csize_t}, Ptr{Ptr{UInt8}}, Ref{Csize_t}),
2826
cd, inbufptr, inbytesleft, outbufptr, outbytesleft)
29-
ccall(Libdl.dlsym_e(h, "iconv_close"), Void, (Ptr{Void},), cd) == -1 && return false
27+
ccall(Libdl.dlsym_e(h, iconv_close), Void, (Ptr{Void},), cd) == -1 && return false
3028

3129
return ret == -1 % Csize_t && Libc.errno() == Libc.EILSEQ
3230
end
3331

34-
libiconv = library_dependency("libiconv", aliases = ["libc", "libc-bin", "iconv"],
35-
validate = validate_iconv)
32+
using BinaryProvider
33+
34+
# Parse some basic command-line arguments
35+
const verbose = "--verbose" in ARGS
36+
const prefix = Prefix(get([a for a in ARGS if a != "--verbose"], 1, joinpath(@__DIR__, "usr")))
37+
products = [
38+
LibraryProduct(prefix, String["libiconv"], :libiconv)
39+
]
40+
41+
# Download binaries from hosted location
42+
bin_prefix = "https://github.com/JuliaStrings/IConvBuilder/releases/download/v1.15+build.2"
3643

37-
if is_windows()
38-
using WinRPM
39-
provides(WinRPM.RPM, "win_iconv-dll", libiconv, os = :Windows)
44+
# Listing of files generated by BinaryBuilder:
45+
download_info = Dict(
46+
BinaryProvider.Linux(:aarch64, :glibc, :blank_abi) => ("$bin_prefix/IConv.aarch64-linux-gnu.tar.gz", "3e6a353988e5089c7b49fb79350d90c31475c10c3d7c1271f889889db53d307f"),
47+
BinaryProvider.Linux(:aarch64, :musl, :blank_abi) => ("$bin_prefix/IConv.aarch64-linux-musl.tar.gz", "2dc859f220a7df89b68e31a1e772a461e288e5b4691ccb2fc76ec0b1e828b98a"),
48+
BinaryProvider.Linux(:armv7l, :glibc, :eabihf) => ("$bin_prefix/IConv.arm-linux-gnueabihf.tar.gz", "43900a0baaaf7b43f8c67ec022bb488cae4972acb958562cfc533294a3acf93e"),
49+
BinaryProvider.Linux(:armv7l, :musl, :eabihf) => ("$bin_prefix/IConv.arm-linux-musleabihf.tar.gz", "2547a615f078af1a877447a06717337bf1588bc7e81d19163b73905902681fe0"),
50+
BinaryProvider.Linux(:i686, :glibc, :blank_abi) => ("$bin_prefix/IConv.i686-linux-gnu.tar.gz", "b7af0081f0d0f5be0020053d811d7dc2d2f1d0349009a0258c19319a2835c490"),
51+
BinaryProvider.Linux(:i686, :musl, :blank_abi) => ("$bin_prefix/IConv.i686-linux-musl.tar.gz", "a3e6869733ec511e2e45347607515cdf05b92b48dfbd5c3cb5e47bdf78cfe4cd"),
52+
BinaryProvider.Windows(:i686, :blank_libc, :blank_abi) => ("$bin_prefix/IConv.i686-w64-mingw32.tar.gz", "247cc617fbc0e059943d905e068171479e1a354c6b59b8a298bfda98ec0230f5"),
53+
BinaryProvider.Linux(:powerpc64le, :glibc, :blank_abi) => ("$bin_prefix/IConv.powerpc64le-linux-gnu.tar.gz", "62bee599a09dfb98e0d410fd93d30188cb0472295f25b9cc05e31dda35904ab8"),
54+
BinaryProvider.MacOS(:x86_64, :blank_libc, :blank_abi) => ("$bin_prefix/IConv.x86_64-apple-darwin14.tar.gz", "1489b867362c1ee6daa8e16361daa7f9d9613a67cb684d1eb8b93b3d74137188"),
55+
BinaryProvider.Linux(:x86_64, :glibc, :blank_abi) => ("$bin_prefix/IConv.x86_64-linux-gnu.tar.gz", "a61ec482c81bca8c1fb3108908481c14d61668fa11b5ef0498badad2119559e5"),
56+
BinaryProvider.Linux(:x86_64, :musl, :blank_abi) => ("$bin_prefix/IConv.x86_64-linux-musl.tar.gz", "75d2b2e02e0ca3cb6efe38be071556d222c7d5a0755c077717eea6391870832f"),
57+
BinaryProvider.FreeBSD(:x86_64, :blank_libc, :blank_abi) => ("$bin_prefix/IConv.x86_64-unknown-freebsd11.1.tar.gz", "144e7e0f6d66178e357f5279a04a92b4aa50051a6061f0eec06045d63dd283f4"),
58+
BinaryProvider.Windows(:x86_64, :blank_libc, :blank_abi) => ("$bin_prefix/IConv.x86_64-w64-mingw32.tar.gz", "e7840895294b82bbacbf1002aa6b3a739b68de31e119c177126a6da5fe7ff227"),
59+
)
60+
61+
# Detect already present libc iconv or libiconv
62+
# (notably for Linux, Mac OS and other Unixes)
63+
found_iconv = false
64+
for lib in ("libc", "libc-bin", "libiconv", "iconv")
65+
if lib in ("libc", "libc-bin")
66+
global iconv_open = :iconv_open
67+
global iconv_close = :iconv_close
68+
global iconv = :iconv
69+
else
70+
global iconv_open = :libiconv_open
71+
global iconv_close = :libiconv_close
72+
global iconv = :libiconv
73+
end
74+
if validate_iconv(lib, iconv_open, iconv_close, iconv)
75+
found_iconv = true
76+
write(joinpath(@__DIR__, "deps.jl"),
77+
"""
78+
## This file autogenerated by Pkg.build(\\"StringEncodings\\").
79+
## Do not edit.
80+
const libiconv = "$lib"
81+
function check_deps()
82+
global libiconv
83+
if Libdl.dlopen_e(libiconv) == C_NULL
84+
error("\$(libiconv) cannot be opened. Please re-run Pkg.build(\\"StringEncodings\\"), and restart Julia.")
85+
end
86+
87+
end
88+
""")
89+
break
90+
end
4091
end
4192

42-
provides(Sources,
43-
URI("http://ftp.gnu.org/pub/gnu/libiconv/libiconv-1.15.tar.gz"),
44-
libiconv,
45-
SHA="ccf536620a45458d26ba83887a983b96827001e92a13847b45e4925cc8913178")
93+
if !found_iconv
94+
iconv_open = :libiconv_open
95+
iconv_close = :libiconv_close
96+
iconv = :libiconv
97+
# Install unsatisfied or updated dependencies:
98+
unsatisfied = any(!satisfied(p; verbose=verbose) for p in products)
99+
if haskey(download_info, platform_key())
100+
url, tarball_hash = download_info[platform_key()]
101+
if unsatisfied || !isinstalled(url, tarball_hash; prefix=prefix)
102+
# Download and install binaries
103+
install(url, tarball_hash; prefix=prefix, force=true, verbose=verbose)
104+
end
105+
elseif unsatisfied
106+
# If we don't have a BinaryProvider-compatible .tar.gz to download, complain.
107+
# Alternatively, you could attempt to install from a separate provider,
108+
# build from source or something even more ambitious here.
109+
error("Your platform $(triplet(platform_key())) is not supported by this package! Try installing libiconv manually.")
110+
end
46111

47-
provides(BuildProcess,
48-
Autotools(libtarget = "lib/libiconv.la",
49-
installed_libname = "libiconv"*BinDeps.shlib_ext),
50-
libiconv,
51-
os = :Unix)
112+
# Write out a deps.jl file that will contain mappings for our products
113+
write_deps_file(joinpath(@__DIR__, "deps.jl"), products)
114+
end
52115

53-
@BinDeps.install Dict(:libiconv => :libiconv)
116+
open(joinpath(@__DIR__, "deps.jl"), "a") do io
117+
write(io,
118+
"""
119+
const iconv_open_s = :$iconv_open
120+
const iconv_close_s = :$iconv_close
121+
const iconv_s = :$iconv
122+
""")
123+
end

src/StringEncodings.jl

+19-8
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,20 @@
11
# This file is a part of StringEncodings.jl. License is MIT: http://julialang.org/license
22

33
module StringEncodings
4+
5+
# Load in `deps.jl`, complaining if it does not exist
6+
const depsjl_path = joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")
7+
if !isfile(depsjl_path)
8+
error("iconv not installed properly, run Pkg.build(\"StringEncodings\"), restart Julia and try again")
9+
end
10+
include(depsjl_path)
11+
12+
# Module initialization function
13+
function __init__()
14+
# Always check dependencies from `deps.jl`
15+
check_deps()
16+
end
17+
418
using Base.Libc: errno, strerror, E2BIG, EINVAL, EILSEQ
519
using Compat: @compat
620

@@ -56,21 +70,18 @@ end
5670
show{T<:Union{IncompleteSequenceError,OutputBufferError}}(io::IO, exc::T) =
5771
print(io, message(T))
5872

59-
depsjl = joinpath(dirname(@__FILE__), "..", "deps", "deps.jl")
60-
isfile(depsjl) ? include(depsjl) : error("libiconv not properly installed. Please run\nPkg.build(\"StringEncodings\")")
61-
6273

6374
## iconv wrappers
6475

6576
function iconv_close(cd::Ptr{Void})
6677
if cd != C_NULL
67-
ccall((:iconv_close, libiconv), Cint, (Ptr{Void},), cd) == 0 ||
78+
ccall((iconv_close_s, libiconv), Cint, (Ptr{Void},), cd) == 0 ||
6879
throw(IConvError("iconv_close"))
6980
end
7081
end
7182

7283
function iconv_open(tocode::String, fromcode::String)
73-
p = ccall((:iconv_open, libiconv), Ptr{Void}, (Cstring, Cstring), tocode, fromcode)
84+
p = ccall((iconv_open_s, libiconv), Ptr{Void}, (Cstring, Cstring), tocode, fromcode)
7485
if p != Ptr{Void}(-1)
7586
return p
7687
elseif errno() == EINVAL
@@ -133,7 +144,7 @@ function iconv!(cd::Ptr{Void}, inbuf::Vector{UInt8}, outbuf::Vector{UInt8},
133144
inbytesleft_orig = inbytesleft[]
134145
outbytesleft[] = BUFSIZE
135146

136-
ret = ccall((:iconv, libiconv), Csize_t,
147+
ret = ccall((iconv_s, libiconv), Csize_t,
137148
(Ptr{Void}, Ptr{Ptr{UInt8}}, Ref{Csize_t}, Ptr{Ptr{UInt8}}, Ref{Csize_t}),
138149
cd, inbufptr, inbytesleft, outbufptr, outbytesleft)
139150

@@ -165,7 +176,7 @@ function iconv_reset!(s::Union{StringEncoder, StringDecoder})
165176

166177
s.outbufptr[] = pointer(s.outbuf)
167178
s.outbytesleft[] = BUFSIZE
168-
ret = ccall((:iconv, libiconv), Csize_t,
179+
ret = ccall((iconv_s, libiconv), Csize_t,
169180
(Ptr{Void}, Ptr{Ptr{UInt8}}, Ref{Csize_t}, Ptr{Ptr{UInt8}}, Ref{Csize_t}),
170181
s.cd, C_NULL, C_NULL, s.outbufptr, s.outbytesleft)
171182

@@ -506,7 +517,7 @@ encode(s::AbstractString, enc::AbstractString) = encode(s, Encoding(enc))
506517

507518
function test_encoding(enc::String)
508519
# We assume that an encoding is supported if it's possible to convert from it to UTF-8:
509-
cd = ccall((:iconv_open, libiconv), Ptr{Void}, (Cstring, Cstring), enc, "UTF-8")
520+
cd = ccall((iconv_open_s, libiconv), Ptr{Void}, (Cstring, Cstring), enc, "UTF-8")
510521
if cd == Ptr{Void}(-1)
511522
return false
512523
else

0 commit comments

Comments
 (0)