Loading...
Searching...
No Matches
JitPlatform.hpp
1#pragma once
2#include <Library/LibrarySettings.hpp>
3
4#include <score/application/ApplicationContext.hpp>
5
6#include <QCoreApplication>
7#include <QDebug>
8#include <QDir>
9#include <QDirIterator>
10#include <QFileInfo>
11#include <QStringList>
12
13#include <llvm/ADT/StringMap.h>
14#include <llvm/ADT/StringRef.h>
15
16#if LLVM_VERSION_MAJOR >= 17
17#include <llvm/TargetParser/Host.h>
18#include <llvm/TargetParser/Triple.h>
19#else
20#include <llvm/Support/Host.h>
21#endif
22
23#include <iostream>
24#include <string>
25#include <vector>
26#include <version>
27#if __has_include(<llvm/Config/llvm-config-64.h>)
28#include <llvm/Config/llvm-config-64.h>
29#elif __has_include(<llvm/Config/llvm-config.h>)
30#include <llvm/Config/llvm-config.h>
31#endif
32
33#if defined(__has_feature)
34#if __has_feature(address_sanitizer) && !defined(__SANITIZE_ADDRESS__)
35#define __SANITIZE_ADDRESS__ 1
36#endif
37#endif
38
39#if defined(SCORE_FHS_BUILD)
40#define SCORE_USE_DISTRO_SYSROOT 1
41#else
42#if defined(SCORE_DEPLOYMENT_BUILD)
43#define SCORE_USE_DISTRO_SYSROOT 0
44#else
45#define SCORE_USE_DISTRO_SYSROOT 1
46#endif
47#endif
48
49#include <JitCpp/JitOptions.hpp>
50
51#include <score_git_info.hpp>
52
53namespace Jit
54{
55
56static inline std::string locateSDK()
57{
58 if(QString sdk = qgetenv("SCORE_JIT_SDK"); !sdk.isEmpty())
59 return sdk.toStdString();
60
61 auto& ctx = score::AppContext().settings<Library::Settings::Model>();
62 QString path = ctx.getSDKPath();
63
64 if(QString libPath = QStringLiteral("%1/%2/usr").arg(path).arg(SCORE_TAG_NO_V);
65 QDir(libPath + "/include/c++").exists())
66 {
67 return libPath.toStdString();
68 }
69
70 if(QString libPath = path + "/usr"; QDir(libPath + "/include/c++").exists())
71 {
72 return libPath.toStdString();
73 }
74
75 auto appFolder = QCoreApplication::instance()->applicationDirPath();
76
77#if !SCORE_FHS_BUILD
78
79#if defined(_WIN32)
80 {
81 QDir d{appFolder};
82 d.cd("sdk");
83 return d.absolutePath().toStdString();
84 }
85#elif defined(__linux__)
86 {
87 QDir d{appFolder};
88 d.cdUp();
89 d.cd("usr");
90 return d.absolutePath().toStdString();
91 }
92#elif defined(__APPLE__)
93 {
94 QDir d{appFolder};
95 d.cdUp();
96 if(d.cd("Frameworks"))
97 {
98 if(d.cd("Score.Framework"))
99 {
100 return d.absolutePath().toStdString();
101 }
102 }
103 auto framework = QString(appFolder + "/Score.Framework");
104 if(QDir{}.exists(framework))
105 return framework.toStdString();
106 else
107 return "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/"
108 "Developer/SDKs/MacOSX.sdk/usr";
109 }
110#endif
111
112#else
113#if defined(__APPLE__)
114 return "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/"
115 "Developer/SDKs/MacOSX.sdk/usr";
116#endif
117 if(QFileInfo("/usr/include/c++").isDir())
118 {
119 return "/usr";
120 }
121 else
122 {
123 return ctx.getSDKPath().toStdString();
124 }
125#endif
126}
127
129{
130 std::string path;
131 enum
132 {
133 none, // Nothing was found
134 platform, // Building against /usr/include, useful for dev builds
135 official // The SDK obtained from official score releases
136 } sdk_kind
137 = none;
138
139// Do we use the score source dir or the headers from the SDK
140#if !SCORE_FHS_BUILD
141 static constexpr bool deploying = true;
142#else
143 static constexpr bool deploying = false;
144#endif
145};
146
147inline located_sdk locateSDKWithFallback()
148{
149 located_sdk ret;
150 ret.path = locateSDK();
151 if(ret.path.empty())
152 ret.sdk_kind = located_sdk::none;
153 if(ret.path.starts_with("/usr") || ret.path.starts_with("/Applications"))
154 ret.sdk_kind = located_sdk::official;
155 else
156 ret.sdk_kind = located_sdk::platform;
157
158 // An explicitly-provided or relocatable SDK (SCORE_JIT_SDK, an AppImage / .app
159 // bundle) can live outside /usr; trust it as official when it actually ships the
160 // deployed score files the addon compiler needs, otherwise prototype and include
161 // resolution wrongly falls back to the build-time source tree (absent at runtime).
162 if(ret.sdk_kind == located_sdk::platform
163 && QDir(QString::fromStdString(ret.path)).exists("lib/cmake/score/prototype.cpp.in"))
164 ret.sdk_kind = located_sdk::official;
165
166 {
167 QDir dir(QString::fromStdString(ret.path));
168 if(!dir.exists())
169 ret.sdk_kind = located_sdk::none;
170
171 if(!dir.cd("include") || !dir.cd("c++"))
172 {
173 qDebug() << "Unable to locate standard headers, fallback to /usr";
174 ret.path = "/usr";
175 dir.setPath("/usr");
176 if(!dir.cd("include") || !dir.cd("c++"))
177 {
178 qDebug() << "Unable to locate any standard headers, install C++ development "
179 "toolchain";
180 throw std::runtime_error("Unable to compile");
181 }
182 ret.sdk_kind = located_sdk::platform;
183 }
184 }
185 return ret;
186}
187
188// Locate the SDK's LLVM ORC runtime archive (compiler-rt orc_rt), if shipped.
189// The native ExecutorNativePlatform loads it into the executor to provide native
190// TLS, static-init/atexit scheduling and (COFF) exception-table registration.
191// Name and location vary per platform (liborc_rt.a / liborc_rt_osx.a /
192// liborc_rt-x86_64.a, under llvm/ or llvm-libs/), so search a few candidate roots
193// rather than hard-coding. Returns "" when absent (e.g. Windows-arm64, or an SDK
194// built before orc_rt was shipped) -- callers then keep the non-platform path.
195static inline std::string locateOrcRuntime()
196{
197 if(QString p = qgetenv("SCORE_JIT_ORC_RUNTIME"); !p.isEmpty())
198 return p.toStdString();
199
200 auto sdk = locateSDKWithFallback();
201 if(sdk.path.empty())
202 return {};
203
204 const QString base = QString::fromStdString(sdk.path);
205 const QString parent = QFileInfo(base).absolutePath();
206 const QStringList roots{base, parent,
207 parent + "/llvm", parent + "/llvm-libs",
208 base + "/llvm", base + "/llvm-libs"};
209 for(const QString& root : roots)
210 {
211 // orc_rt lives under the clang resource dir: <root>/lib/clang/<v>/lib/<t>/.
212 const QString clangLibs = root + "/lib/clang";
213 if(!QDir(clangLibs).exists())
214 continue;
215 QDirIterator it(
216 clangLibs, {"liborc_rt*.a"}, QDir::Files, QDirIterator::Subdirectories);
217 if(it.hasNext())
218 return it.next().toStdString();
219 }
220 return {};
221}
222
223// Locate compiler-rt's builtins archive (libclang_rt.builtins-*.a). clang's driver
224// links it via -rtlib=compiler-rt; the JIT compiles with bare -cc1 (no driver), so
225// builtins such as __udivti3 (128-bit integer division, pulled by fmt and others)
226// are otherwise unresolved. We hand it to ORC as a definition generator. Same
227// search roots as locateOrcRuntime (it lives in the same clang resource dir);
228// prefer the COFF/windows variant. Returns "" when absent.
229static inline std::string locateBuiltinsRuntime()
230{
231 if(QString p = qgetenv("SCORE_JIT_BUILTINS"); !p.isEmpty())
232 return p.toStdString();
233
234 auto sdk = locateSDKWithFallback();
235 if(sdk.path.empty())
236 return {};
237
238 const QString base = QString::fromStdString(sdk.path);
239 const QString parent = QFileInfo(base).absolutePath();
240 const QStringList roots{base, parent,
241 parent + "/llvm", parent + "/llvm-libs",
242 base + "/llvm", base + "/llvm-libs"};
243 QString fallback;
244 for(const QString& root : roots)
245 {
246 const QString clangLibs = root + "/lib/clang";
247 if(!QDir(clangLibs).exists())
248 continue;
249 QDirIterator it(
250 clangLibs, {"libclang_rt.builtins*.a"}, QDir::Files,
251 QDirIterator::Subdirectories);
252 while(it.hasNext())
253 {
254 const QString f = it.next();
255 if(f.contains("/windows/") || f.contains("\\windows\\"))
256 return f.toStdString(); // prefer the COFF/windows variant
257 if(fallback.isEmpty())
258 fallback = f;
259 }
260 }
261 return fallback.toStdString();
262}
263
264// Locates a mingw-w64 CRT-support archive (libmingwex.a, libucrt.a, ...) that
265// the driver links implicitly into every mingw executable but the JIT's bare
266// -cc1 compile does not. libmingwex supplies the C99-name math functions the
267// UCRT only exports under their underscore names (e.g. hypotf wraps _hypot)
268// plus routines the CRT lacks entirely; libucrt's alias objects supply the
269// POSIX old names (fileno -> _fileno) and renamed imports (__msvcrt_assert).
270static inline std::string locateMingwRuntimeLib(const char* env, const char* name)
271{
272 if(QString p = qgetenv(env); !p.isEmpty())
273 return p.toStdString();
274
275 auto sdk = locateSDKWithFallback();
276 if(sdk.path.empty())
277 return {};
278
279 const QString base = QString::fromStdString(sdk.path);
280 const QString parent = QFileInfo(base).absolutePath();
281 const QStringList roots{base, parent,
282 parent + "/llvm", parent + "/llvm-libs",
283 base + "/llvm", base + "/llvm-libs"};
284 const QString lib = QString::fromUtf8(name);
285 for(const QString& root : roots)
286 {
287 // Shipped runtime SDK layout (create-sdk-mingw.sh) and toolchain layout.
288 for(const QString& p :
289 {QString(root + "/lib/" + lib),
290 QString(root + "/x86_64-w64-mingw32/lib/" + lib)})
291 if(QFile::exists(p))
292 return p.toStdString();
293 }
294 return {};
295}
296
297static inline std::string locateMingwexRuntime()
298{
299 return locateMingwRuntimeLib("SCORE_JIT_MINGWEX", "libmingwex.a");
300}
301
302static inline std::string locateUcrtImportLib()
303{
304 return locateMingwRuntimeLib("SCORE_JIT_UCRT", "libucrt.a");
305}
306
307static inline void
308populateCompileOptions(std::vector<std::string>& args, CompilerOptions opts)
309{
310 args.push_back("-triple");
311 const std::string processTriple = llvm::sys::getProcessTriple();
312 args.push_back(processTriple);
313
314 // On Windows/COFF the JIT maps the add-on at a high address (the reserved slab)
315 // and must reference far host symbols -- libc++abi RTTI vtables and the EH
316 // personality among them. The small (default) code model emits 32-bit
317 // relocations that truncate at that address, corrupting vtables / type_info and
318 // crashing __dynamic_cast (notably multiple-inheritance / cross-casts during
319 // plugin registration). The large code model uses 64-bit references throughout.
320 // (The JIT TargetMachine also requests Large, but this cc1 module flag is the
321 // authoritative one that actually reaches code generation.)
322 if(llvm::Triple(processTriple).isOSBinFormatCOFF())
323 {
324 args.push_back("-mcmodel=large");
325
326 // Mirror the target flags clang's *driver* injects for x86_64-w64-windows-gnu
327 // that this bare -cc1 invocation would otherwise miss. Without them the add-on
328 // is compiled differently from how score itself was built (score goes through
329 // the driver + bin/*.cfg), which is what makes host symbols fail to resolve:
330 // -D_UCRT select the Universal CRT, so printf/fprintf bind to the
331 // UCRT (__stdio_common_vfprintf -- which score imports)
332 // instead of legacy-msvcrt mingw ANSI stdio
333 // (__mingw_printf / __mingw_fprintf, absent from score).
334 // -fno-use-init-array COFF static ctors emit into .ctors (which
335 // MinGWCOFFPlatform collects), not .init_array.
336 // -funwind-tables=2 / -fno-sized-deallocation match the driver's SEH
337 // unwind-table emission and operator-delete ABI.
338 args.push_back("-D_UCRT");
339 // The JIT unconditionally passes -D_GNU_SOURCE=1 (below) for POSIX features on
340 // Linux add-ons; score itself does not define it. On mingw, _GNU_SOURCE flips
341 // __USE_MINGW_ANSI_STDIO to 1 (an independent term of that decision, so _UCRT
342 // alone doesn't undo it), which routes printf/fprintf to legacy-msvcrt
343 // __mingw_printf / __mingw_fprintf -- symbols score (UCRT) doesn't contain.
344 // Force the UCRT stdio path so the add-on binds the same printf family score
345 // does (__stdio_common_vfprintf), resolvable from the host process.
346 args.push_back("-D__USE_MINGW_ANSI_STDIO=0");
347 args.push_back("-fno-use-init-array");
348 args.push_back("-funwind-tables=2");
349 args.push_back("-fno-sized-deallocation");
350 }
351
352 args.push_back("-target-cpu");
353 args.push_back(llvm::sys::getHostCPUName().lower());
354
355 {
356 llvm::StringMap<bool> HostFeatures;
357#if LLVM_VERSION_MAJOR < 19
358 bool ok = llvm::sys::getHostCPUFeatures(HostFeatures);
359#else
360 constexpr bool ok = true;
361 HostFeatures = llvm::sys::getHostCPUFeatures();
362#endif
363 if(ok)
364 {
365 for(const llvm::StringMapEntry<bool>& F : HostFeatures)
366 {
367 args.push_back("-target-feature");
368 args.push_back((F.second ? "+" : "-") + F.first().str());
369 }
370 }
371 }
372
373 // Match the dialect score itself is built with (gnu++23, not strict c++23):
374 // avnd/halp/ossia rely on GNU extensions (anonymous structs/unions, etc.) that
375 // strict -std=c++23 (__STRICT_ANSI__) rejects or types differently, which makes
376 // some nodes that build fine in score fail to compile in the JIT (e.g. curve
377 // controls: the curve_segment concept then isn't satisfied and make_segment has
378 // no viable overload).
379 args.push_back("-std=gnu++23");
380 args.push_back("-disable-free");
381 args.push_back("-fdeprecated-macro");
382 args.push_back("-fmath-errno");
383 // disappeared in clang 11 args.push_back("-fuse-init-array");
384
385 // args.push_back("-mrelocation-model");
386 // args.push_back("static");
387 args.push_back("-mthread-model");
388 args.push_back("posix");
389 // disappeared in clang 11 args.push_back("-masm-verbose");
390 args.push_back("-mconstructor-aliases");
391
392 // args.push_back("-dwarf-column-info");
393 // args.push_back("-debugger-tuning=gdb");
394
395 args.push_back("-fno-use-cxa-atexit");
396
397 // -Ofast stuff:
398 // args.push_back("-menable-unsafe-fp-math");
399 args.push_back("-fno-signed-zeros");
400 args.push_back("-mreassociate");
401 args.push_back("-freciprocal-math");
402 args.push_back("-fno-rounding-math");
403
404 // disappeared in clang 12 args.push_back("-fno-trapping-math");
405 args.push_back("-ffp-contract=fast");
406
407#if !defined(__linux__) // || (defined(__linux__) && __GLIBC_MINOR__ >= 31)
408 // isn't that great
409 // https://reviews.llvm.org/D74712
410 args.push_back("-Ofast");
411 args.push_back("-menable-no-infs");
412 args.push_back("-menable-no-nans");
413 args.push_back("-ffinite-math-only");
414 args.push_back("-ffast-math");
415#else
416 args.push_back("-O3");
417 args.push_back("-fno-builtin");
418#endif
419
420 // Prevent emitting ___chkstk_ms calls in alloca
421 args.push_back("-mno-stack-arg-probe");
422
423 args.push_back("-fgnuc-version=4.2.1");
424
425#if defined(__APPLE__)
426 args.push_back("-fmax-type-align=16");
427
428 // Apple framework headers (CoreGraphics, ImageIO, Metadata, ...) declare
429 // block-typed parameters (`void (^)(...)`), the Apple "blocks" extension. The
430 // JIT pulls them in transitively, so enable blocks or every such declaration is
431 // a hard error ("blocks support disabled - compile with -fblocks"). We only
432 // parse these signatures; the add-on does not invoke them, so no blocks runtime
433 // is needed.
434 args.push_back("-fblocks");
435
436 // Apple's CoreFoundation CF_ENUM / CF_OPTIONS macros expand (when the fixed
437 // underlying type is available, as in C++) to a non-defining fixed-underlying-
438 // type enum embedded in a typedef, e.g. `typedef enum E : long E; enum E : long
439 // {...};`. That form is only valid in Objective-C(++) where objc_fixed_enum is
440 // a feature; in plain C++23 clang rejects it as -Welaborated-enum-base. The JIT
441 // compiles the addon as C++ but pulls these headers in transitively (Qt, ossia),
442 // so accept the Apple idiom as the extension it is. clang still assigns the enum
443 // its correct fixed-type values.
444 args.push_back("-Wno-elaborated-enum-base");
445#endif
446 args.push_back("-mrelocation-model");
447 args.push_back("pic");
448 args.push_back("-pic-level");
449 args.push_back("2");
450 //args.push_back("-pic-is-pie");
451
452 // changed from -fvisibility hidden to -fvisibility=hidden in clang 16
453 args.push_back("-fvisibility=hidden");
454
455 args.push_back("-fvisibility-inlines-hidden");
456
457 // TLS: when an Orc Platform (orc_rt) drives the executor we get *native*
458 // thread-locals on every target, and TargetOptions.EmulatedTLS is set false
459 // (see Compiler.cpp). In that case we must NOT force emulated TLS here: codegen
460 // would emit __emutls_* references the platform does not provide. Only request
461 // emulated/local-exec TLS on the legacy (no-orc_rt) path. This mirrors
462 // useNativePlatform in Compiler.cpp (same locateOrcRuntime() result).
463#if LLVM_VERSION_MAJOR >= 22
464 const bool useNativePlatform = !locateOrcRuntime().empty();
465#else
466 const bool useNativePlatform = false;
467#endif
468 // COFF has no JIT-usable native TLS (no _tls_index / .tls directory), so force
469 // emulated TLS there even with the platform on -- matching TargetOptions in
470 // Compiler.cpp. __emutls_get_address resolves from the compiler-rt builtins
471 // archive in the add-on link order.
472 if(!useNativePlatform || llvm::Triple(processTriple).isOSBinFormatCOFF())
473 {
474 args.push_back("-ftls-model=local-exec");
475 args.push_back("-femulated-tls");
476 }
477
478 // if fsanitize:
479 args.push_back("-mrelax-all");
480 args.push_back("-disable-llvm-verifier");
481 args.push_back("-discard-value-names");
482#if defined(__SANITIZE_ADDRESS__)
483 /*
484
485 args.push_back(
486 "-fsanitize=address,alignment,array-bounds,bool,builtin,enum,float-cast-"
487 "overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-"
488 "attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-"
489 "base,shift-exponent,signed-integer-overflow,unreachable,vla-bound,vptr,"
490 "unsigned-integer-overflow,implicit-integer-truncation");
491 args.push_back(
492 "-fsanitize-recover=alignment,array-bounds,bool,builtin,enum,float-cast-"
493 "overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-"
494 "attribute,null,pointer-overflow,returns-nonnull-attribute,shift-base,"
495 "shift-exponent,signed-integer-overflow,vla-bound,vptr,unsigned-integer-"
496 "overflow,implicit-integer-truncation");
497 args.push_back(
498 "-fsanitize-blacklist=/usr/lib/clang/7.0.0/share/asan_blacklist.txt");
499 args.push_back("-fsanitize-address-use-after-scope");
500 args.push_back("-mdisable-fp-elim");
501 */
502#endif
503 args.push_back("-fno-assume-sane-operator-new");
504 // args.push_back("-fcoroutines-ts");
505 args.push_back("-stack-protector");
506 args.push_back("0");
507 if(opts.NoExceptions)
508 {
509 args.push_back("-fno-rtti");
510 }
511 else
512 {
513#if LLVM_VERSION_MAJOR <= 13
514 args.push_back("-munwind-tables");
515#endif
516
517 args.push_back("-fcxx-exceptions");
518 args.push_back("-fexceptions");
519 args.push_back("-fexternc-nounwind");
520#if defined(_WIN32)
521 args.push_back("-exception-model=seh");
522#endif
523 }
524 args.push_back("-faddrsig");
525
526 // args.push_back("-momit-leaf-frame-pointer");
527 args.push_back("-vectorize-loops");
528 args.push_back("-vectorize-slp");
529}
530
531static inline void populateDefinitions(std::vector<std::string>& args)
532{
533#if defined(__APPLE__)
534 // needed because otherwise readerwriterqueue includes CoreFoundation.h ...
535 args.push_back("-DMOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE=");
536#endif
537#define XSTR(s) STR(s)
538#define STR(s) #s
539
540#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
541 args.push_back("-DBOOST_ASIO_ENABLE_BUFFER_DEBUGGING");
542#endif
543#if defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT)
544 args.push_back(
545 "-DBOOST_ASIO_HAS_STD_INVOKE_RESULT=" XSTR(BOOST_ASIO_HAS_STD_INVOKE_RESULT));
546#endif
547#if defined(BOOST_MATH_DISABLE_FLOAT128)
548 args.push_back("-DBOOST_MATH_DISABLE_FLOAT128=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
549#endif
550#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
551 args.push_back("-DBOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING");
552#endif
553#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
554 args.push_back("-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE");
555#endif
556#if defined(BOOST_NO_RTTI)
557 args.push_back("-DBOOST_NO_RTTI=" XSTR(BOOST_NO_RTTI));
558#endif
559#if defined(FMT_SHARED)
560 args.push_back("-DFMT_SHARED=" XSTR(FMT_SHARED));
561#endif
562 // score/libossia link fmt as header-only in deployment builds (see
563 // libossia/cmake/deps/fmt.cmake), so fmt's functions are inlined into score and
564 // no fmt archive/symbols are exported. An add-on compiled WITHOUT
565 // FMT_HEADER_ONLY emits external references (e.g. fmt::vprint) that the host
566 // cannot resolve -- JIT load then fails with "Symbols not found: fmt::...".
567 // Propagate the same mode score itself was built with so the add-on inlines fmt.
568#if defined(FMT_HEADER_ONLY)
569 args.push_back("-DFMT_HEADER_ONLY=" XSTR(FMT_HEADER_ONLY));
570#endif
571#if defined(FMT_STATIC_THOUSANDS_SEPARATOR)
572 args.push_back(
573 "-DFMT_STATIC_THOUSANDS_SEPARATOR=" XSTR(FMT_STATIC_THOUSANDS_SEPARATOR));
574#endif
575#if defined(FMT_USE_FLOAT128)
576 args.push_back("-DFMT_USE_FLOAT128=" XSTR(FMT_USE_FLOAT128));
577#endif
578#if defined(FMT_USE_INT128)
579 args.push_back("-DFMT_USE_INT128=" XSTR(FMT_USE_INT128));
580#endif
581#if defined(FMT_USE_LONG_DOUBLE)
582 args.push_back("-DFMT_USE_LONG_DOUBLE=" XSTR(FMT_USE_LONG_DOUBLE));
583#endif
584#if defined(LIBREMIDI_ALSA)
585 args.push_back("-DLIBREMIDI_ALSA");
586#endif
587#if defined(LIBREMIDI_HAS_JACK_GET_VERSION)
588 args.push_back("-DLIBREMIDI_HAS_JACK_GET_VERSION");
589#endif
590#if defined(LIBREMIDI_HAS_UDEV)
591 args.push_back("-DLIBREMIDI_HAS_UDEV");
592#endif
593#if defined(LIBREMIDI_JACK)
594 args.push_back("-DLIBREMIDI_JACK");
595#endif
596#if defined(LIBREMIDI_KEYBOARD)
597 args.push_back("-DLIBREMIDI_KEYBOARD");
598#endif
599#if defined(LIBREMIDI_PIPEWIRE)
600 args.push_back("-DLIBREMIDI_PIPEWIRE");
601#endif
602#if defined(LIBREMIDI_PIPEWIRE_UMP)
603 args.push_back("-DLIBREMIDI_PIPEWIRE_UMP");
604#endif
605#if defined(LIBREMIDI_USE_BOOST)
606 args.push_back("-DLIBREMIDI_USE_BOOST");
607#endif
608#if defined(LIBREMIDI_WEAKJACK)
609 args.push_back("-DLIBREMIDI_WEAKJACK");
610#endif
611#if defined(QT_CORE_LIB)
612 args.push_back("-DQT_CORE_LIB");
613#endif
614#if defined(QT_DISABLE_DEPRECATED_BEFORE)
615 args.push_back("-DQT_DISABLE_DEPRECATED_BEFORE=" XSTR(QT_DISABLE_DEPRECATED_BEFORE));
616#endif
617#if defined(QT_GUI_LIB)
618 args.push_back("-DQT_GUI_LIB");
619#endif
620#if defined(QT_NETWORK_LIB)
621 args.push_back("-DQT_NETWORK_LIB");
622#endif
623#if defined(QT_NO_JAVA_STYLE_ITERATORS)
624 args.push_back("-DQT_NO_JAVA_STYLE_ITERATORS");
625#endif
626#if defined(QT_NO_KEYWORDS)
627 args.push_back("-DQT_NO_KEYWORDS");
628#endif
629#if defined(QT_NO_LINKED_LIST)
630 args.push_back("-DQT_NO_LINKED_LIST");
631#endif
632#if defined(QT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
633 args.push_back("-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT");
634#endif
635#if defined(QT_NO_USING_NAMESPACE)
636 args.push_back("-DQT_NO_USING_NAMESPACE");
637#endif
638#if defined(QT_OPENGL_LIB)
639 args.push_back("-DQT_OPENGL_LIB");
640#endif
641#if defined(QT_QMLINTEGRATION_LIB)
642 args.push_back("-DQT_QMLINTEGRATION_LIB");
643#endif
644#if defined(QT_QML_LIB)
645 args.push_back("-DQT_QML_LIB");
646#endif
647#if defined(QT_SERIALPORT_LIB)
648 args.push_back("-DQT_SERIALPORT_LIB");
649#endif
650#if defined(QT_SHADERTOOLS_LIB)
651 args.push_back("-DQT_SHADERTOOLS_LIB");
652#endif
653#if defined(QT_STATEMACHINE_LIB)
654 args.push_back("-DQT_STATEMACHINE_LIB");
655#endif
656#if defined(QT_USE_QSTRINGBUILDER)
657 args.push_back("-DQT_USE_QSTRINGBUILDER");
658#endif
659#if defined(QT_WEBSOCKETS_LIB)
660 args.push_back("-DQT_WEBSOCKETS_LIB");
661#endif
662#if defined(QT_WIDGETS_LIB)
663 args.push_back("-DQT_WIDGETS_LIB");
664#endif
665#if defined(RAPIDJSON_HAS_STDSTRING)
666 args.push_back("-DRAPIDJSON_HAS_STDSTRING=" XSTR(RAPIDJSON_HAS_STDSTRING));
667#endif
668#if defined(SCORE_DEBUG)
669 args.push_back("-DSCORE_DEBUG");
670#endif
671#if defined(SCORE_LIB_BASE)
672 args.push_back("-DSCORE_LIB_BASE");
673#endif
674#if defined(SCORE_LIB_DEVICE)
675 args.push_back("-DSCORE_LIB_DEVICE");
676#endif
677#if defined(SCORE_LIB_INSPECTOR)
678 args.push_back("-DSCORE_LIB_INSPECTOR");
679#endif
680#if defined(SCORE_LIB_LOCALTREE)
681 args.push_back("-DSCORE_LIB_LOCALTREE");
682#endif
683#if defined(SCORE_LIB_PROCESS)
684 args.push_back("-DSCORE_LIB_PROCESS");
685#endif
686#if defined(SCORE_LIB_STATE)
687 args.push_back("-DSCORE_LIB_STATE");
688#endif
689#if defined(SCORE_PLUGIN_AUDIO)
690 args.push_back("-DSCORE_PLUGIN_AUDIO");
691#endif
692#if defined(SCORE_PLUGIN_AUTOMATION)
693 args.push_back("-DSCORE_PLUGIN_AUTOMATION");
694#endif
695#if defined(SCORE_PLUGIN_AVND)
696 args.push_back("-DSCORE_PLUGIN_AVND");
697#endif
698#if defined(SCORE_PLUGIN_CURVE)
699 args.push_back("-DSCORE_PLUGIN_CURVE");
700#endif
701#if defined(SCORE_PLUGIN_DATAFLOW)
702 args.push_back("-DSCORE_PLUGIN_DATAFLOW");
703#endif
704#if defined(SCORE_PLUGIN_DEVICEEXPLORER)
705 args.push_back("-DSCORE_PLUGIN_DEVICEEXPLORER");
706#endif
707#if defined(SCORE_PLUGIN_ENGINE)
708 args.push_back("-DSCORE_PLUGIN_ENGINE");
709#endif
710#if defined(SCORE_PLUGIN_GFX)
711 args.push_back("-DSCORE_PLUGIN_GFX");
712#endif
713#if defined(SCORE_PLUGIN_LIBRARY)
714 args.push_back("-DSCORE_PLUGIN_LIBRARY");
715#endif
716#if defined(SCORE_PLUGIN_MEDIA)
717 args.push_back("-DSCORE_PLUGIN_MEDIA");
718#endif
719#if defined(SCORE_PLUGIN_SCENARIO)
720 args.push_back("-DSCORE_PLUGIN_SCENARIO");
721#endif
722#if defined(SCORE_PLUGIN_TRANSPORT)
723 args.push_back("-DSCORE_PLUGIN_TRANSPORT");
724#endif
725#if defined(SERVUS_USE_AVAHI_CLIENT)
726 args.push_back("-DSERVUS_USE_AVAHI_CLIENT");
727#endif
728#if defined(SPDLOG_COMPILED_LIB)
729 args.push_back("-DSPDLOG_COMPILED_LIB=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
730#endif
731#if defined(SPDLOG_DEBUG_ON)
732 args.push_back("-DSPDLOG_DEBUG_ON=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
733#endif
734#if defined(SPDLOG_FMT_EXTERNAL)
735 args.push_back("-DSPDLOG_FMT_EXTERNAL=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
736#endif
737#if defined(SPDLOG_NO_DATETIME)
738 args.push_back("-DSPDLOG_NO_DATETIME=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
739#endif
740#if defined(SPDLOG_NO_NAME)
741 args.push_back("-DSPDLOG_NO_NAME=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
742#endif
743#if defined(SPDLOG_NO_THREAD_ID)
744 args.push_back("-DSPDLOG_NO_THREAD_ID=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
745#endif
746#if defined(SPDLOG_SHARED_LIB)
747 args.push_back("-DSPDLOG_SHARED_LIB=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
748#endif
749#if defined(SPDLOG_TRACE_ON)
750 args.push_back("-DSPDLOG_TRACE_ON=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
751#endif
752#if defined(TINYSPLINE_DOUBLE_PRECISION)
753 args.push_back("-DTINYSPLINE_DOUBLE_PRECISION");
754#endif
755
756#if defined(SCORE_DEBUG)
757 args.push_back("-DSCORE_DEBUG");
758#endif
759
760 // args.push_back("-DSCORE_STATIC_PLUGINS");
761 args.push_back("-D_GNU_SOURCE=1");
762 args.push_back("-D__STDC_CONSTANT_MACROS");
763 args.push_back("-D__STDC_FORMAT_MACROS");
764 args.push_back("-D__STDC_LIMIT_MACROS");
765#if defined(FFTW_SINGLE_ONLY)
766 args.push_back("-DFFTW_SINGLE_ONLY");
767#elif defined(FFTW_DOUBLE_ONLY)
768 args.push_back("-DFFTW_DOUBLE_ONLY");
769#endif
770}
771
772static inline auto getPotentialTriples()
773{
774 std::vector<QString> triples;
775 triples.push_back(LLVM_DEFAULT_TARGET_TRIPLE);
776 triples.push_back(LLVM_HOST_TRIPLE);
777#if defined(__x86_64__)
778 triples.push_back("x86_64-pc-linux-gnu");
779 triples.push_back("x86_64-unknown-linux-gnu");
780#elif defined(__i686__)
781 triples.push_back("i686-pc-linux-gnu");
782#elif defined(__i586__)
783 triples.push_back("i586-pc-linux-gnu");
784#elif defined(__i486__)
785 triples.push_back("i486-pc-linux-gnu");
786#elif defined(__i386__)
787 triples.push_back("i386-pc-linux-gnu");
788#elif defined(__arm__)
789 triples.push_back("armv8-none-linux-gnueabi");
790 triples.push_back("armv8-pc-linux-gnueabi");
791 triples.push_back("armv8-none-linux-gnu");
792 triples.push_back("armv8-pc-linux-gnu");
793 triples.push_back("armv7-none-linux-gnueabi");
794 triples.push_back("armv7-pc-linux-gnueabi");
795 triples.push_back("armv7-none-linux-gnu");
796 triples.push_back("armv7-pc-linux-gnu");
797 triples.push_back("armv6-none-linux-gnueabi");
798 triples.push_back("armv6-pc-linux-gnueabi");
799 triples.push_back("armv6-none-linux-gnu");
800 triples.push_back("armv6-pc-linux-gnu");
801#elif defined(__aarch64__)
802 triples.push_back("aarch64-none-linux-gnueabi");
803 triples.push_back("aarch64-pc-linux-gnueabi");
804 triples.push_back("aarch64-unknown-linux-gnueabi");
805 triples.push_back("aarch64-none-linux-gnu");
806 triples.push_back("aarch64-pc-linux-gnu");
807 triples.push_back("aarch64-unknown-linux-gnu");
808 triples.push_back("aarch64-redhat-linux");
809#endif
810
811 return triples;
812}
852static inline void populateIncludeDirs(std::vector<std::string>& args)
853{
854 auto sdk_location = locateSDKWithFallback();
855 auto& sdk = sdk_location.path;
856 auto qsdk = QString::fromStdString(sdk);
857
858 qDebug() << "SDK located: " << qsdk;
859 std::string llvm_lib_version = SCORE_LLVM_VERSION;
860#if defined(__APPLE__) && SCORE_FHS_BUILD
861 llvm_lib_version = "13.0.0";
862#endif
863
864 QDir resDir = QString(qsdk + "/lib/clang");
865 auto entries = resDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
866 if(!entries.empty() && !entries.contains(SCORE_LLVM_VERSION))
867 llvm_lib_version = entries.front().toStdString();
868
869#if defined(__APPLE__) && SCORE_FHS_BUILD
870 std::string appleSharedSdk
871 = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/"
872 "usr";
873 args.push_back("-resource-dir");
874 args.push_back(appleSharedSdk + "/lib/clang/" + llvm_lib_version);
875#else
876 args.push_back("-resource-dir");
877 args.push_back(sdk + "/lib/clang/" + llvm_lib_version);
878#endif
879
880#if defined(_LIBCPP_VERSION)
881 args.push_back("-stdlib=libc++");
882 args.push_back("-internal-isystem");
883
884#if defined(__APPLE__) && SCORE_FHS_BUILD
885 args.push_back(appleSharedSdk + "/include/c++/v1");
886#else
887 args.push_back(sdk + "/include/c++/v1");
888#endif
889
890 // libc++'s per-target __config_site lives at include/<triple>/c++/v1 (multiarch
891 // layout) and is #include'd by the main libc++ headers, so that dir must also be
892 // on the search path.
893 {
894 const QDir incdir(qsdk + "/include");
895 for(const auto& d : incdir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
896 {
897 if(QFileInfo::exists(qsdk + "/include/" + d + "/c++/v1/__config_site"))
898 {
899 args.push_back("-internal-isystem");
900 args.push_back(sdk + "/include/" + d.toStdString() + "/c++/v1");
901 break;
902 }
903 }
904 }
905
906#elif defined(_GLIBCXX_RELEASE)
907 // Try to locate the correct libstdc++ folder
908 // TODO these are only heuristics. how to make them better ?
909 {
910 const auto libstdcpp_major = QString::number(_GLIBCXX_RELEASE);
911
912 QDir cpp_dir{"/usr/include/c++"};
913 // Note: as this is only used for debugging we look in the host /usr
914 QDirIterator cpp_it{cpp_dir};
915 while(cpp_it.hasNext())
916 {
917 cpp_it.next();
918 auto ver = cpp_it.fileName();
919 if(!ver.isEmpty() && ver.startsWith(libstdcpp_major))
920 {
921 auto gcc = ver.toStdString();
922
923 // e.g. /usr/include/c++/8.2.1
924 args.push_back("-internal-isystem");
925 args.push_back("/usr/include/c++/" + gcc);
926
927 cpp_dir.cd(ver);
928 for(auto& triple : getPotentialTriples())
929 {
930 if(cpp_dir.exists(triple))
931 {
932 // e.g. /usr/include/c++/8.2.1/x86_64-pc-linux-gnu
933 args.push_back("-internal-isystem");
934 args.push_back("/usr/include/c++/" + gcc + "/" + triple.toStdString());
935 break;
936 }
937 }
938
939 break;
940 }
941 }
942 }
943#endif
944
945#if defined(__APPLE__) && SCORE_FHS_BUILD
946 args.push_back("-internal-isystem");
947 args.push_back(appleSharedSdk + "/lib/clang/" + llvm_lib_version + "/include");
948 args.push_back("-internal-externc-isystem");
949 args.push_back(
950 "/Applications/Xcode.app/Contents/Developer//Platforms/MacOSX.platform/Developer/"
951 "SDKs/MacOSX.sdk/usr/include");
952#else
953 args.push_back("-internal-isystem");
954 args.push_back(sdk + "/lib/clang/" + llvm_lib_version + "/include");
955 args.push_back("-internal-externc-isystem");
956 args.push_back(sdk + "/include");
957#endif
958
959#if defined(__APPLE__)
960 // macOS framework headers are bundled flat in the SDK under include/macos-sdks
961 // (e.g. macos-sdks/ApplicationServices/ApplicationServices.h). In -cc1 mode no
962 // default framework path is added, so addons that transitively include a system
963 // framework (e.g. ApplicationServices via score/tools/Cursor.hpp) need this.
964 if(QFileInfo{qsdk + "/include/macos-sdks"}.isDir())
965 args.push_back("-isystem" + sdk + "/include/macos-sdks");
966#endif
967
968 // -resource-dir
969 // /opt/score-sdk/llvm/lib/clang/11.0.0
970 // -internal-isystem
971 // /opt/score-sdk/llvm/bin/../include/c++/v1
972 // -internal-isystem
973 // /opt/score-sdk/llvm/lib/clang/11.0.0/include
974 //-internal-externc-isystem
976
977 auto include = [&](const std::string& path) {
978 std::string path_to_include = sdk + "/include/" + path;
979 auto qpath = QString::fromStdString(path_to_include);
980 if(!QFileInfo{qpath}.isDir())
981 {
982 qDebug() << "Trying to include non-existent path: " << qpath;
983 }
984 else
985 {
986 args.push_back("-isystem" + sdk + "/include/" + path);
987 }
988 };
989
990#if defined(__linux__)
991// #debian
992#if defined(__x86_64__)
993 include("x86_64-linux-gnu");
994#else
995 include("aarch64-linux-gnu");
996#endif
997#endif
998
999 // include(""); // /usr/include
1000 std::string qt_folder = "qt";
1001 if(QFile::exists(qsdk + "/include/qt6/QtCore"))
1002 qt_folder = "qt6";
1003
1004 QDirIterator qtVersionFolder{
1005 qsdk + "/include/" + QString::fromStdString(qt_folder) + "/QtCore",
1006 {},
1007 QDir::Filter::Dirs | QDir::Filter::NoDotAndDotDot,
1008 {}};
1009 std::string qt_version = QT_VERSION_STR;
1010 if(qtVersionFolder.hasNext())
1011 {
1012 QDir sub = qtVersionFolder.next();
1013 qt_version = sub.dirName().toStdString();
1014 }
1015 include(qt_folder + "");
1016 include(qt_folder + "/QtCore");
1017 include(qt_folder + "/QtCore/" + qt_version);
1018 include(qt_folder + "/QtCore/" + qt_version + "/QtCore");
1019 include(qt_folder + "/QtGui");
1020 include(qt_folder + "/QtGui/" + qt_version);
1021 include(qt_folder + "/QtGui/" + qt_version + "/QtGui");
1022 include(qt_folder + "/QtWidgets");
1023 include(qt_folder + "/QtWidgets/" + qt_version);
1024 include(qt_folder + "/QtWidgets/" + qt_version + "/QtWidgets");
1025 include(qt_folder + "/QtQml");
1026 include(qt_folder + "/QtQml/" + qt_version);
1027 include(qt_folder + "/QtQml/" + qt_version + "/QtQml");
1028 include(qt_folder + "/QtQuick");
1029 include(qt_folder + "/QtQuick/" + qt_version);
1030 include(qt_folder + "/QtQuick/" + qt_version + "/QtQuick");
1031 include(qt_folder + "/QtXml");
1032 include(qt_folder + "/QtNetwork");
1033 include(qt_folder + "/QtSvg");
1034 include(qt_folder + "/QtSql");
1035 include(qt_folder + "/QtOpenGL");
1036 include(qt_folder + "/QtShaderTools");
1037 include(qt_folder + "/QtShaderTools/" + qt_version);
1038 include(qt_folder + "/QtShaderTools/" + qt_version + "/QtShaderTools");
1039 include(qt_folder + "/QtSerialPort");
1040
1041 if(sdk_location.sdk_kind == located_sdk::official && sdk_location.deploying)
1042 {
1043 include("score");
1044 }
1045 else
1046 {
1047 auto thirdparty_include_dirs = {
1048 "/3rdparty/libossia/3rdparty/boost_1_88_0",
1049 "/3rdparty/libossia/3rdparty/nano-signal-slot/include",
1050 "/3rdparty/libossia/3rdparty/spdlog/include",
1051 "/3rdparty/libossia/3rdparty/dr_libs",
1052 "/3rdparty/libossia/3rdparty/Flicks",
1053 "/3rdparty/libossia/3rdparty/fmt/include",
1054 "/3rdparty/libossia/3rdparty/magic_enum/include",
1055 "/3rdparty/libossia/3rdparty/readerwriterqueue",
1056 "/3rdparty/libossia/3rdparty/concurrentqueue",
1057 "/3rdparty/libossia/3rdparty/SmallFunction/smallfun/include",
1058 "/3rdparty/libossia/3rdparty/websocketpp",
1059 "/3rdparty/libossia/3rdparty/rapidjson/include",
1060 "/3rdparty/libossia/3rdparty/libremidi/include",
1061 "/3rdparty/libossia/3rdparty/oscpack",
1062 "/3rdparty/libossia/3rdparty/rnd/include",
1063 "/3rdparty/libossia/3rdparty/span/include",
1064 "/3rdparty/libossia/3rdparty/tuplet/include",
1065 "/3rdparty/libossia/3rdparty/unordered_dense/include",
1066 "/3rdparty/libossia/3rdparty/multi_index/include",
1067 "/3rdparty/libossia/3rdparty/verdigris/src",
1068 "/3rdparty/libossia/3rdparty/weakjack",
1069 };
1070 for(auto path : thirdparty_include_dirs)
1071 {
1072 args.push_back("-isystem" + std::string(SCORE_ROOT_SOURCE_DIR) + path);
1073 }
1074 auto src_include_dirs
1075 = {"/3rdparty/libossia/src",
1076 "/3rdparty/avendish/include",
1077 "/src/lib",
1078 "/src/plugins/score-lib-state",
1079 "/src/plugins/score-lib-device",
1080 "/src/plugins/score-lib-process",
1081 "/src/plugins/score-lib-inspector",
1082 "/src/plugins/score-plugin-avnd",
1083 "/src/plugins/score-plugin-gfx",
1084 "/src/plugins/score-plugin-jit",
1085 "/src/plugins/score-plugin-nodal",
1086 "/src/plugins/score-plugin-remotecontrol",
1087 "/src/plugins/score-plugin-audio",
1088 "/src/plugins/score-plugin-curve",
1089 "/src/plugins/score-plugin-dataflow",
1090 "/src/plugins/score-plugin-engine",
1091 "/src/plugins/score-plugin-scenario",
1092 "/src/plugins/score-plugin-library",
1093 "/src/plugins/score-plugin-deviceexplorer",
1094 "/src/plugins/score-plugin-media",
1095 "/src/plugins/score-plugin-loop",
1096 "/src/plugins/score-plugin-midi",
1097 "/src/plugins/score-plugin-protocols",
1098 "/src/plugins/score-plugin-recording",
1099 "/src/plugins/score-plugin-automation",
1100 "/src/plugins/score-plugin-js",
1101 "/src/plugins/score-plugin-mapping"};
1102
1103 for(auto path : src_include_dirs)
1104 {
1105 args.push_back("-I" + std::string(SCORE_ROOT_SOURCE_DIR) + path);
1106 }
1107
1108 auto src_build_dirs
1109 = {"/.",
1110 "/src/lib",
1111 "/src/plugins/score-lib-state",
1112 "/src/plugins/score-lib-device",
1113 "/src/plugins/score-lib-process",
1114 "/src/plugins/score-lib-inspector",
1115 "/src/plugins/score-plugin-avnd",
1116 "/src/plugins/score-plugin-gfx",
1117 "/src/plugins/score-plugin-jit",
1118 "/src/plugins/score-plugin-nodal",
1119 "/src/plugins/score-plugin-remotecontrol",
1120 "/src/plugins/score-plugin-audio",
1121 "/src/plugins/score-plugin-curve",
1122 "/src/plugins/score-plugin-dataflow",
1123 "/src/plugins/score-plugin-engine",
1124 "/src/plugins/score-plugin-scenario",
1125 "/src/plugins/score-plugin-library",
1126 "/src/plugins/score-plugin-deviceexplorer",
1127 "/src/plugins/score-plugin-media",
1128 "/src/plugins/score-plugin-loop",
1129 "/src/plugins/score-plugin-midi",
1130 "/src/plugins/score-plugin-protocols",
1131 "/src/plugins/score-plugin-recording",
1132 "/src/plugins/score-plugin-automation",
1133 "/src/plugins/score-plugin-js",
1134 "/src/plugins/score-plugin-mapping",
1135 "/3rdparty/libossia/src"};
1136
1137 for(auto path : src_build_dirs)
1138 {
1139 args.push_back("-I" + std::string(SCORE_ROOT_BINARY_DIR) + path);
1140 }
1141 }
1142}
1143
1144}
Definition LibrarySettings.hpp:46
Definition JitPlatform.hpp:129
T & settings() const
Access a specific Settings model instance.
Definition ApplicationContext.hpp:41