-
Notifications
You must be signed in to change notification settings - Fork 1
/
install-filcrypto
executable file
·216 lines (175 loc) · 7.75 KB
/
install-filcrypto
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#!/usr/bin/env bash
# shellcheck disable=SC2155 enable=require-variable-braces
set -Exeo pipefail
auth_header=()
if [ -n "${GITHUB_TOKEN}" ]; then
auth_header=("-H" "Authorization: token ${GITHUB_TOKEN}")
fi
# set CWD to the root of filecoin-ffi
#
cd "$(dirname "${BASH_SOURCE[0]}")"
# tracks where the Rust sources are were we to build locally instead of
# downloading from GitHub Releases
#
rust_sources_dir="rust"
# an array of values passed as 'target-feature' to the Rust compiler if we're
# building an optimized libfilcrypto (which takes advantage of some perf-boosting
# instruction sets)
#
optimized_release_rustc_target_features=$(jq -r '.[].rustc_target_feature' < "${rust_sources_dir}/rustc-target-features-optimized.json")
# each value in this area is checked against the "features" of the hosts CPU
# in order to determine if the host is suitable for an optimized release
#
cpu_features_required_for_optimized_release=$(jq -r '.[].check_cpu_for_feature | select(. != null)' < "${rust_sources_dir}/rustc-target-features-optimized.json")
main() {
local __release_type=$(get_release_type)
if [ "${FFI_BUILD_FROM_SOURCE}" != "1" ] && download_release_tarball __tarball_path "${rust_sources_dir}" "filecoin-ffi" "${__release_type}"; then
local __tmp_dir=$(mktemp -d)
# silence shellcheck warning as the assignment happened in
# `download_release_tarball()`
# shellcheck disable=SC2154
# extract downloaded tarball to temporary directory
#
tar -C "${__tmp_dir}" -xzf "${__tarball_path}"
# copy build assets into root of filecoin-ffi
#
find -L "${__tmp_dir}" -type f -name filcrypto.h -exec cp -- "{}" . \;
find -L "${__tmp_dir}" -type f -name libfilcrypto.a -exec cp -- "{}" . \;
find -L "${__tmp_dir}" -type f -name filcrypto.pc -exec cp -- "{}" . \;
check_installed_files
(>&2 echo "[install-filcrypto/main] successfully installed prebuilt libfilcrypto")
else
(>&2 echo "[install-filcrypto/main] building libfilcrypto from local sources (dir = ${rust_sources_dir})")
# build libfilcrypto (and corresponding header and pkg-config)
#
build_from_source "filcrypto" "${rust_sources_dir}" "${__release_type}"
# copy from Rust's build directory (target) to root of filecoin-ffi
#
find -L "${rust_sources_dir}/target/release" -type f -name filcrypto.h -exec cp -- "{}" . \;
find -L "${rust_sources_dir}/target/release" -type f -name libfilcrypto.a -exec cp -- "{}" . \;
find -L "${rust_sources_dir}" -type f -name filcrypto.pc -exec cp -- "{}" . \;
check_installed_files
(>&2 echo "[install-filcrypto/main] successfully built and installed libfilcrypto from source")
fi
}
download_release_tarball() {
local __resultvar=$1
local __rust_sources_path=$2
local __repo_name=$3
local __release_type=$4
local __release_sha1=$(git rev-parse HEAD)
local __release_tag="${__release_sha1:0:16}"
local __release_tag_url="https://api.github.com/repos/filecoin-project/${__repo_name}/releases/tags/${__release_tag}"
# TODO: This function shouldn't make assumptions about how these releases'
# names are constructed. Marginally less-bad would be to require that this
# function's caller provide the release name.
#
local __release_name="${__repo_name}-$(uname)-${__release_type}"
(>&2 echo "[download_release_tarball] acquiring release @ ${__release_tag}")
local __release_response=$(curl "${auth_header[@]}" \
--retry 3 \
--location "${__release_tag_url}")
local __release_url=$(echo "${__release_response}" | jq -r ".assets[] | select(.name | contains(\"${__release_name}\")) | .url")
local __tar_path="/tmp/${__release_name}_$(basename "${__release_url}").tar.gz"
if [[ -z "${__release_url}" ]]; then
(>&2 echo "[download_release_tarball] failed to download release (tag URL: ${__release_tag_url}, response: ${__release_response})")
return 1
fi
local __asset_url=$(curl "${auth_header[@]}" \
--head \
--retry 3 \
--header "Accept:application/octet-stream" \
--location \
--output /dev/null \
-w "%{url_effective}" \
"${__release_url}")
if ! curl --retry 3 --output "${__tar_path}" "${__asset_url}"; then
(>&2 echo "[download_release_tarball] failed to download release asset (tag URL: ${__release_tag_url}, asset URL: ${__asset_url})")
return 1
fi
# set $__resultvar (which the caller provided as $1), which is the poor
# man's way of returning a value from a function in Bash
#
eval "${__resultvar}='${__tar_path}'"
}
build_from_source() {
local __library_name=$1
local __rust_sources_path=$2
local __release_type=$3
local __repo_sha1=$(git rev-parse HEAD)
local __repo_sha1_truncated="${__repo_sha1:0:16}"
local __target_feature=""
(>&2 echo "building from source @ ${__repo_sha1_truncated}")
if ! [ -x "$(command -v cargo)" ]; then
(>&2 echo '[build_from_source] Error: cargo is not installed.')
(>&2 echo '[build_from_source] install Rust toolchain to resolve this problem.')
exit 1
fi
if ! [ -x "$(command -v rustup)" ]; then
(>&2 echo '[build_from_source] Error: rustup is not installed.')
(>&2 echo '[build_from_source] install Rust toolchain installer to resolve this problem.')
exit 1
fi
pushd "${__rust_sources_path}"
cargo --version
# reduce array of features into the rustc-specific 'target-feature' flag
# shellcheck disable=SC2068 # the splitting is intentional
for x in ${optimized_release_rustc_target_features[@]}; do
__target_feature="${x},${__target_feature}"
done
if [ "${__release_type}" = "optimized" ]; then
RUSTFLAGS="-C target-feature=${__target_feature}" ./scripts/build-release.sh "${__library_name}" "$(cat rust-toolchain)"
else
./scripts/build-release.sh "${__library_name}" "$(cat rust-toolchain)"
fi
popd
}
get_release_type() {
local __searched=""
local __features=""
local __optimized=true
# determine where to look for CPU features
#
if [[ ! -f "/proc/cpuinfo" ]]; then
(>&2 echo "[get_release_type] no /proc/cpuinfo file; falling back to Darwin feature detection")
__searched="sysctl -a | grep machdep.cpu | tr '[:upper:]' '[:lower:]' | grep features"
else
__searched="cat /proc/cpuinfo | grep flags"
fi
__features=$(eval "${__searched}")
# check for the presence of each required CPU feature
#
# shellcheck disable=SC2068 # the splitting is intentional
for x in ${cpu_features_required_for_optimized_release[@]}; do
if [ "${__optimized}" = true ]; then
if [ -n "${__features##*${x}*}" ]; then
(>&2 echo "[get_release_type] your CPU does not support the '${x}' feature (searched '${__searched}')")
__optimized=false
fi
fi
done
# if we couldn't figure out where to look for features, use standard
#
if [ "${__optimized}" == true ] && [ -n "${__features}" ]; then
(>&2 echo "[get_release_type] configuring 'optimized' build")
echo "optimized"
else
(>&2 echo "[get_release_type] configuring 'standard' build")
echo "standard"
fi
}
check_installed_files() {
if [[ ! -f "./filcrypto.h" ]]; then
(>&2 echo "[check_installed_files] failed to install filcrypto.h")
exit 1
fi
if [[ ! -f "./libfilcrypto.a" ]]; then
(>&2 echo "[check_installed_files] failed to install libfilcrypto.a")
exit 1
fi
if [[ ! -f "./filcrypto.pc" ]]; then
(>&2 echo "[check_installed_files] failed to install filcrypto.pc")
exit 1
fi
}
main "$@"; exit