nixpkgs mirror (for testing)
github.com/NixOS/nixpkgs
nix
1{ stdenv
2, fetchFromGitHub
3, fetchpatch
4, fetchzip
5, writeText
6, lib
7, openssl
8, cmake
9, autoconf
10, automake
11, libtool
12, pkg-config
13, bison
14, flex
15, groff
16, perl
17, python3
18, ncurses
19, time
20, upx
21, gtest
22, libffi
23, libxml2
24, zlib
25, enableTests ? true
26, buildDevTools ? true
27, compileYaraPatterns ? true
28}:
29
30let
31 # all dependencies that are normally fetched during build time (the subdirectories of `deps`)
32 # all of these need to be fetched through nix and applied via their <NAME>_URL cmake variable
33 capstone = fetchFromGitHub {
34 owner = "capstone-engine";
35 repo = "capstone";
36 rev = "5.0-rc2";
37 sha256 = "sha256-nB7FcgisBa8rRDS3k31BbkYB+tdqA6Qyj9hqCnFW+ME=";
38 };
39 llvm = fetchFromGitHub {
40 owner = "avast-tl";
41 repo = "llvm";
42 rev = "2a1f3d8a97241c6e91710be8f84cf3cf80c03390";
43 sha256 = "sha256-+v1T0VI9R92ed9ViqsfYZMJtPCjPHCr4FenoYdLuFOU=";
44 };
45 yaracpp = fetchFromGitHub {
46 owner = "VirusTotal";
47 repo = "yara";
48 rev = "v4.2.0-rc1";
49 sha256 = "sha256-WcN6ClYO2d+/MdG06RHx3kN0o0WVAY876dJiG7CwJ8w=";
50 };
51 yaramod = fetchFromGitHub {
52 owner = "avast";
53 repo = "yaramod";
54 rev = "aa06dd408c492a8f4488774caf2ee105ccc23ab5";
55 sha256 = "sha256-NVDRf2U5H92EN/Ks//uxNEaeKU+sT4VL4QyyYMO+zKk=";
56 };
57 keystone = fetchFromGitHub {
58 # only for tests
59 owner = "keystone-engine";
60 repo = "keystone";
61 rev = "d7ba8e378e5284e6384fc9ecd660ed5f6532e922";
62 sha256 = "1yzw3v8xvxh1rysh97y0i8y9svzbglx2zbsqjhrfx18vngh0x58f";
63 };
64
65 retdec-support-version = "2019-03-08";
66 retdec-support =
67 { rev = retdec-support-version; } // # for checking the version against the expected version
68 fetchzip {
69 url = "https://github.com/avast-tl/retdec-support/releases/download/${retdec-support-version}/retdec-support_${retdec-support-version}.tar.xz";
70 hash = "sha256-t1tx4MfLW/lwtbO5JQ1nrFBIOeMclq+0dENuXW+ahIM=";
71 stripRoot = false;
72 };
73
74 check-dep = name: dep:
75 ''
76 context="$(grep ${name}_URL --after-context 1 cmake/deps.cmake)"
77 expected="$(echo "$context" | grep --only-matching '".*"')"
78 have="${dep.rev}"
79
80 echo "checking ${name} dependency matches deps.cmake...";
81 if ! echo "$expected" | grep -q "$have"; then
82 printf '%s\n' "${name} version does not match!" " nix: $have, expected: $expected"
83 false
84 fi
85 '';
86
87 deps = {
88 CAPSTONE = capstone;
89 LLVM = llvm;
90 YARA = yaracpp;
91 YARAMOD = yaramod;
92 SUPPORT_PKG = retdec-support;
93 } // lib.optionalAttrs enableTests {
94 KEYSTONE = keystone;
95 # nixpkgs googletest is used
96 # GOOGLETEST = googletest;
97 };
98
99 # overwrite install-share.py to copy instead of download.
100 # we use this so the copy happens at the right time in the build,
101 # otherwise, the build process cleans the directory.
102 install-share =
103 writeText
104 "install-share.py"
105 ''
106 import os, sys, shutil, subprocess
107
108 install_path, arch_url, sha256hash_ref, version = sys.argv[1:]
109 support_dir = os.path.join(install_path, 'share', 'retdec', 'support')
110
111 assert os.path.isdir(arch_url), "nix install-share.py expects a path for support url"
112
113 os.makedirs(support_dir, exist_ok=True)
114 shutil.copytree(arch_url, support_dir, dirs_exist_ok=True)
115 subprocess.check_call(['chmod', '-R', 'u+w', support_dir])
116 '';
117in
118stdenv.mkDerivation (self: {
119 pname = "retdec";
120
121 # If you update this you will also need to adjust the versions of the updated dependencies.
122 # I've notified upstream about this problem here:
123 # https://github.com/avast-tl/retdec/issues/412
124 #
125 # The dependencies and their sources are listed in this file:
126 # https://github.com/avast/retdec/blob/master/cmake/deps.cmake
127 version = "5.0";
128
129 src = fetchFromGitHub {
130 owner = "avast";
131 repo = "retdec";
132 rev = "refs/tags/v${self.version}";
133 sha256 = "sha256-H4e+aSgdBBbG6X6DzHGiDEIASPwBVNVsfHyeBTQLAKI=";
134 };
135
136 patches = [
137 # gcc 13 compatibility: https://github.com/avast/retdec/pull/1153
138 (fetchpatch {
139 url = "https://github.com/avast/retdec/commit/dbaab2c3d17b1eae22c581e8ab6bfefadf4ef6ae.patch";
140 hash = "sha256-YqHYPGAGWT4x6C+CpsOSsOIZ+NPM2FBQtGQFs74OUIQ=";
141 })
142 ];
143
144 nativeBuildInputs = [
145 cmake
146 autoconf
147 automake
148 libtool
149 pkg-config
150 bison
151 flex
152 groff
153 perl
154 python3
155 ];
156
157 buildInputs = [
158 openssl
159 ncurses
160 libffi
161 libxml2
162 zlib
163 ] ++ lib.optional self.doInstallCheck gtest;
164
165 cmakeFlags = [
166 (lib.cmakeBool "RETDEC_TESTS" self.doInstallCheck) # build tests
167 (lib.cmakeBool "RETDEC_DEV_TOOLS" buildDevTools) # build tools e.g. capstone2llvmir, retdectool
168 (lib.cmakeBool "RETDEC_COMPILE_YARA" compileYaraPatterns) # build and install compiled patterns
169 ] ++ lib.mapAttrsToList (k: v: lib.cmakeFeature "${k}_URL" "${v}") deps;
170
171 preConfigure =
172 lib.concatStringsSep "\n" (lib.mapAttrsToList check-dep deps)
173 +
174 ''
175 cp -v ${install-share} ./support/install-share.py
176
177 # the CMakeLists assume CMAKE_INSTALL_BINDIR, etc are path components but in Nix, they are absolute.
178 # therefore, we need to remove the unnecessary CMAKE_INSTALL_PREFIX prepend.
179 substituteInPlace ./CMakeLists.txt \
180 --replace-warn "''$"{CMAKE_INSTALL_PREFIX}/"''$"{RETDEC_INSTALL_BIN_DIR} "''$"{CMAKE_INSTALL_FULL_BINDIR} \
181 --replace-warn "''$"{CMAKE_INSTALL_PREFIX}/"''$"{RETDEC_INSTALL_LIB_DIR} "''$"{CMAKE_INSTALL_FULL_LIBDIR} \
182
183 # --replace "''$"{CMAKE_INSTALL_PREFIX}/"''$"{RETDEC_INSTALL_SUPPORT_DIR} "''$"{RETDEC_INSTALL_SUPPORT_DIR}
184 # note! Nix does not set CMAKE_INSTALL_DATADIR to an absolute path, so this replacement would be incorrect
185
186 # similarly for yaramod. here, we fix the LIBDIR to lib64. for whatever reason, only "lib64" works.
187 substituteInPlace deps/yaramod/CMakeLists.txt \
188 --replace-fail "''$"{YARAMOD_INSTALL_DIR}/"''$"{CMAKE_INSTALL_LIBDIR} "''$"{YARAMOD_INSTALL_DIR}/lib64 \
189 --replace-fail CMAKE_ARGS 'CMAKE_ARGS -DCMAKE_INSTALL_LIBDIR=lib64'
190
191 # yara needs write permissions in the generated source directory.
192 echo ${lib.escapeShellArg ''
193 ExternalProject_Add_Step(
194 yara chmod WORKING_DIRECTORY ''${YARA_DIR}
195 DEPENDEES download COMMAND chmod -R u+w .
196 )
197 ''} >> deps/yara/CMakeLists.txt
198
199 # patch gtest to use the system package
200 gtest=deps/googletest/CMakeLists.txt
201 old="$(cat $gtest)"
202 (echo 'find_package(GTest REQUIRED)'; echo "$old") > $gtest
203 sed -i 's/ExternalProject_[^(]\+[(]/ set(IGNORED /g' $gtest
204
205 substituteInPlace $gtest \
206 --replace-fail '$'{GTEST_LIB} "GTest::gtest"\
207 --replace-fail '$'{GMOCK_LIB} "GTest::gmock"\
208 --replace-fail '$'{GTEST_MAIN_LIB} "GTest::gtest_main"\
209 --replace-fail '$'{GMOCK_MAIN_LIB} "GTest::gmock_main"
210
211 # without git history, there is no chance these tests will pass.
212 substituteInPlace tests/utils/version_tests.cpp \
213 --replace-quiet VersionTests DISABLED_VersionTests
214
215 substituteInPlace scripts/retdec-utils.py \
216 --replace-warn /usr/bin/time ${time} \
217 --replace-warn /usr/local/bin/gtime ${time}
218 substituteInPlace scripts/retdec-unpacker.py \
219 --replace-warn "'upx'" "'${upx}'"
220 '';
221
222 doInstallCheck = enableTests;
223 installCheckPhase = ''
224 ${python3.interpreter} "$out/bin/retdec-tests-runner.py"
225
226 rm -rf $out/bin/__pycache__
227 '';
228
229 meta = with lib; {
230 description = "Retargetable machine-code decompiler based on LLVM";
231 homepage = "https://retdec.com";
232 license = licenses.mit;
233 maintainers = with maintainers; [ katrinafyi ];
234 platforms = [ "x86_64-linux" ];
235 };
236})