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 // Must agree with TargetOptions::EmulatedTLS in Compiler.cpp.
473 if(!useNativePlatform || !llvm::Triple(processTriple).isOSBinFormatMachO())
474 {
475 args.push_back("-ftls-model=local-exec");
476 args.push_back("-femulated-tls");
477 }
478 else
479 {
480 // A hidden thread_local cannot be preempted, so clang picks local-exec for it
481 // even at PIC level 2, emitting an offset into the initial TLS block that
482 // JIT-loaded code is not in. One such variable fails the whole add-on.
483 args.push_back("-ftls-model=global-dynamic");
484 }
485
486 // if fsanitize:
487 args.push_back("-mrelax-all");
488 args.push_back("-disable-llvm-verifier");
489 args.push_back("-discard-value-names");
490#if defined(__SANITIZE_ADDRESS__)
491 /*
492
493 args.push_back(
494 "-fsanitize=address,alignment,array-bounds,bool,builtin,enum,float-cast-"
495 "overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-"
496 "attribute,null,pointer-overflow,return,returns-nonnull-attribute,shift-"
497 "base,shift-exponent,signed-integer-overflow,unreachable,vla-bound,vptr,"
498 "unsigned-integer-overflow,implicit-integer-truncation");
499 args.push_back(
500 "-fsanitize-recover=alignment,array-bounds,bool,builtin,enum,float-cast-"
501 "overflow,float-divide-by-zero,function,integer-divide-by-zero,nonnull-"
502 "attribute,null,pointer-overflow,returns-nonnull-attribute,shift-base,"
503 "shift-exponent,signed-integer-overflow,vla-bound,vptr,unsigned-integer-"
504 "overflow,implicit-integer-truncation");
505 args.push_back(
506 "-fsanitize-blacklist=/usr/lib/clang/7.0.0/share/asan_blacklist.txt");
507 args.push_back("-fsanitize-address-use-after-scope");
508 args.push_back("-mdisable-fp-elim");
509 */
510#endif
511 args.push_back("-fno-assume-sane-operator-new");
512 // args.push_back("-fcoroutines-ts");
513 args.push_back("-stack-protector");
514 args.push_back("0");
515 if(opts.NoExceptions)
516 {
517 args.push_back("-fno-rtti");
518 }
519 else
520 {
521#if LLVM_VERSION_MAJOR <= 13
522 args.push_back("-munwind-tables");
523#endif
524
525 args.push_back("-fcxx-exceptions");
526 args.push_back("-fexceptions");
527 args.push_back("-fexternc-nounwind");
528#if defined(_WIN32)
529 args.push_back("-exception-model=seh");
530#endif
531 }
532 args.push_back("-faddrsig");
533
534 // args.push_back("-momit-leaf-frame-pointer");
535 args.push_back("-vectorize-loops");
536 args.push_back("-vectorize-slp");
537}
538
539static inline void populateDefinitions(std::vector<std::string>& args)
540{
541#if defined(__APPLE__)
542 // needed because otherwise readerwriterqueue includes CoreFoundation.h ...
543 args.push_back("-DMOODYCAMEL_MAYBE_ALIGN_TO_CACHELINE=");
544#endif
545#define XSTR(s) STR(s)
546#define STR(s) #s
547
548#if defined(BOOST_ASIO_ENABLE_BUFFER_DEBUGGING)
549 args.push_back("-DBOOST_ASIO_ENABLE_BUFFER_DEBUGGING");
550#endif
551#if defined(BOOST_ASIO_HAS_STD_INVOKE_RESULT)
552 args.push_back(
553 "-DBOOST_ASIO_HAS_STD_INVOKE_RESULT=" XSTR(BOOST_ASIO_HAS_STD_INVOKE_RESULT));
554#endif
555#if defined(BOOST_MATH_DISABLE_FLOAT128)
556 args.push_back("-DBOOST_MATH_DISABLE_FLOAT128=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
557#endif
558#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)
559 args.push_back("-DBOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING");
560#endif
561#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
562 args.push_back("-DBOOST_MULTI_INDEX_ENABLE_SAFE_MODE");
563#endif
564#if defined(BOOST_NO_RTTI)
565 args.push_back("-DBOOST_NO_RTTI=" XSTR(BOOST_NO_RTTI));
566#endif
567#if defined(FMT_SHARED)
568 args.push_back("-DFMT_SHARED=" XSTR(FMT_SHARED));
569#endif
570 // score/libossia link fmt as header-only in deployment builds (see
571 // libossia/cmake/deps/fmt.cmake), so fmt's functions are inlined into score and
572 // no fmt archive/symbols are exported. An add-on compiled WITHOUT
573 // FMT_HEADER_ONLY emits external references (e.g. fmt::vprint) that the host
574 // cannot resolve -- JIT load then fails with "Symbols not found: fmt::...".
575 // Propagate the same mode score itself was built with so the add-on inlines fmt.
576#if defined(FMT_HEADER_ONLY)
577 args.push_back("-DFMT_HEADER_ONLY=" XSTR(FMT_HEADER_ONLY));
578#endif
579#if defined(FMT_STATIC_THOUSANDS_SEPARATOR)
580 args.push_back(
581 "-DFMT_STATIC_THOUSANDS_SEPARATOR=" XSTR(FMT_STATIC_THOUSANDS_SEPARATOR));
582#endif
583#if defined(FMT_USE_FLOAT128)
584 args.push_back("-DFMT_USE_FLOAT128=" XSTR(FMT_USE_FLOAT128));
585#endif
586#if defined(FMT_USE_INT128)
587 args.push_back("-DFMT_USE_INT128=" XSTR(FMT_USE_INT128));
588#endif
589#if defined(FMT_USE_LONG_DOUBLE)
590 args.push_back("-DFMT_USE_LONG_DOUBLE=" XSTR(FMT_USE_LONG_DOUBLE));
591#endif
592#if defined(LIBREMIDI_ALSA)
593 args.push_back("-DLIBREMIDI_ALSA");
594#endif
595#if defined(LIBREMIDI_HAS_JACK_GET_VERSION)
596 args.push_back("-DLIBREMIDI_HAS_JACK_GET_VERSION");
597#endif
598#if defined(LIBREMIDI_HAS_UDEV)
599 args.push_back("-DLIBREMIDI_HAS_UDEV");
600#endif
601#if defined(LIBREMIDI_JACK)
602 args.push_back("-DLIBREMIDI_JACK");
603#endif
604#if defined(LIBREMIDI_KEYBOARD)
605 args.push_back("-DLIBREMIDI_KEYBOARD");
606#endif
607#if defined(LIBREMIDI_PIPEWIRE)
608 args.push_back("-DLIBREMIDI_PIPEWIRE");
609#endif
610#if defined(LIBREMIDI_PIPEWIRE_UMP)
611 args.push_back("-DLIBREMIDI_PIPEWIRE_UMP");
612#endif
613#if defined(LIBREMIDI_USE_BOOST)
614 args.push_back("-DLIBREMIDI_USE_BOOST");
615#endif
616#if defined(LIBREMIDI_WEAKJACK)
617 args.push_back("-DLIBREMIDI_WEAKJACK");
618#endif
619#if defined(QT_CORE_LIB)
620 args.push_back("-DQT_CORE_LIB");
621#endif
622#if defined(QT_DISABLE_DEPRECATED_BEFORE)
623 args.push_back("-DQT_DISABLE_DEPRECATED_BEFORE=" XSTR(QT_DISABLE_DEPRECATED_BEFORE));
624#endif
625#if defined(QT_GUI_LIB)
626 args.push_back("-DQT_GUI_LIB");
627#endif
628#if defined(QT_NETWORK_LIB)
629 args.push_back("-DQT_NETWORK_LIB");
630#endif
631#if defined(QT_NO_JAVA_STYLE_ITERATORS)
632 args.push_back("-DQT_NO_JAVA_STYLE_ITERATORS");
633#endif
634#if defined(QT_NO_KEYWORDS)
635 args.push_back("-DQT_NO_KEYWORDS");
636#endif
637#if defined(QT_NO_LINKED_LIST)
638 args.push_back("-DQT_NO_LINKED_LIST");
639#endif
640#if defined(QT_NO_NARROWING_CONVERSIONS_IN_CONNECT)
641 args.push_back("-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT");
642#endif
643#if defined(QT_NO_USING_NAMESPACE)
644 args.push_back("-DQT_NO_USING_NAMESPACE");
645#endif
646#if defined(QT_OPENGL_LIB)
647 args.push_back("-DQT_OPENGL_LIB");
648#endif
649#if defined(QT_QMLINTEGRATION_LIB)
650 args.push_back("-DQT_QMLINTEGRATION_LIB");
651#endif
652#if defined(QT_QML_LIB)
653 args.push_back("-DQT_QML_LIB");
654#endif
655#if defined(QT_SERIALPORT_LIB)
656 args.push_back("-DQT_SERIALPORT_LIB");
657#endif
658#if defined(QT_SHADERTOOLS_LIB)
659 args.push_back("-DQT_SHADERTOOLS_LIB");
660#endif
661#if defined(QT_STATEMACHINE_LIB)
662 args.push_back("-DQT_STATEMACHINE_LIB");
663#endif
664#if defined(QT_USE_QSTRINGBUILDER)
665 args.push_back("-DQT_USE_QSTRINGBUILDER");
666#endif
667#if defined(QT_WEBSOCKETS_LIB)
668 args.push_back("-DQT_WEBSOCKETS_LIB");
669#endif
670#if defined(QT_WIDGETS_LIB)
671 args.push_back("-DQT_WIDGETS_LIB");
672#endif
673#if defined(RAPIDJSON_HAS_STDSTRING)
674 args.push_back("-DRAPIDJSON_HAS_STDSTRING=" XSTR(RAPIDJSON_HAS_STDSTRING));
675#endif
676#if defined(SCORE_DEBUG)
677 args.push_back("-DSCORE_DEBUG");
678#endif
679#if defined(SCORE_LIB_BASE)
680 args.push_back("-DSCORE_LIB_BASE");
681#endif
682#if defined(SCORE_LIB_DEVICE)
683 args.push_back("-DSCORE_LIB_DEVICE");
684#endif
685#if defined(SCORE_LIB_INSPECTOR)
686 args.push_back("-DSCORE_LIB_INSPECTOR");
687#endif
688#if defined(SCORE_LIB_LOCALTREE)
689 args.push_back("-DSCORE_LIB_LOCALTREE");
690#endif
691#if defined(SCORE_LIB_PROCESS)
692 args.push_back("-DSCORE_LIB_PROCESS");
693#endif
694#if defined(SCORE_LIB_STATE)
695 args.push_back("-DSCORE_LIB_STATE");
696#endif
697#if defined(SCORE_PLUGIN_AUDIO)
698 args.push_back("-DSCORE_PLUGIN_AUDIO");
699#endif
700#if defined(SCORE_PLUGIN_AUTOMATION)
701 args.push_back("-DSCORE_PLUGIN_AUTOMATION");
702#endif
703#if defined(SCORE_PLUGIN_AVND)
704 args.push_back("-DSCORE_PLUGIN_AVND");
705#endif
706#if defined(SCORE_PLUGIN_CURVE)
707 args.push_back("-DSCORE_PLUGIN_CURVE");
708#endif
709#if defined(SCORE_PLUGIN_DATAFLOW)
710 args.push_back("-DSCORE_PLUGIN_DATAFLOW");
711#endif
712#if defined(SCORE_PLUGIN_DEVICEEXPLORER)
713 args.push_back("-DSCORE_PLUGIN_DEVICEEXPLORER");
714#endif
715#if defined(SCORE_PLUGIN_ENGINE)
716 args.push_back("-DSCORE_PLUGIN_ENGINE");
717#endif
718#if defined(SCORE_PLUGIN_GFX)
719 args.push_back("-DSCORE_PLUGIN_GFX");
720#endif
721#if defined(SCORE_PLUGIN_LIBRARY)
722 args.push_back("-DSCORE_PLUGIN_LIBRARY");
723#endif
724#if defined(SCORE_PLUGIN_MEDIA)
725 args.push_back("-DSCORE_PLUGIN_MEDIA");
726#endif
727#if defined(SCORE_PLUGIN_SCENARIO)
728 args.push_back("-DSCORE_PLUGIN_SCENARIO");
729#endif
730#if defined(SCORE_PLUGIN_TRANSPORT)
731 args.push_back("-DSCORE_PLUGIN_TRANSPORT");
732#endif
733#if defined(SERVUS_USE_AVAHI_CLIENT)
734 args.push_back("-DSERVUS_USE_AVAHI_CLIENT");
735#endif
736#if defined(SPDLOG_COMPILED_LIB)
737 args.push_back("-DSPDLOG_COMPILED_LIB=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
738#endif
739#if defined(SPDLOG_DEBUG_ON)
740 args.push_back("-DSPDLOG_DEBUG_ON=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
741#endif
742#if defined(SPDLOG_FMT_EXTERNAL)
743 args.push_back("-DSPDLOG_FMT_EXTERNAL=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
744#endif
745#if defined(SPDLOG_NO_DATETIME)
746 args.push_back("-DSPDLOG_NO_DATETIME=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
747#endif
748#if defined(SPDLOG_NO_NAME)
749 args.push_back("-DSPDLOG_NO_NAME=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
750#endif
751#if defined(SPDLOG_NO_THREAD_ID)
752 args.push_back("-DSPDLOG_NO_THREAD_ID=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
753#endif
754#if defined(SPDLOG_SHARED_LIB)
755 args.push_back("-DSPDLOG_SHARED_LIB=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
756#endif
757#if defined(SPDLOG_TRACE_ON)
758 args.push_back("-DSPDLOG_TRACE_ON=" XSTR(BOOST_MATH_DISABLE_FLOAT128));
759#endif
760#if defined(TINYSPLINE_DOUBLE_PRECISION)
761 args.push_back("-DTINYSPLINE_DOUBLE_PRECISION");
762#endif
763
764#if defined(SCORE_DEBUG)
765 args.push_back("-DSCORE_DEBUG");
766#endif
767
768 // args.push_back("-DSCORE_STATIC_PLUGINS");
769 args.push_back("-D_GNU_SOURCE=1");
770 args.push_back("-D__STDC_CONSTANT_MACROS");
771 args.push_back("-D__STDC_FORMAT_MACROS");
772 args.push_back("-D__STDC_LIMIT_MACROS");
773#if defined(FFTW_SINGLE_ONLY)
774 args.push_back("-DFFTW_SINGLE_ONLY");
775#elif defined(FFTW_DOUBLE_ONLY)
776 args.push_back("-DFFTW_DOUBLE_ONLY");
777#endif
778}
779
780static inline auto getPotentialTriples()
781{
782 std::vector<QString> triples;
783 triples.push_back(LLVM_DEFAULT_TARGET_TRIPLE);
784 triples.push_back(LLVM_HOST_TRIPLE);
785#if defined(__x86_64__)
786 triples.push_back("x86_64-pc-linux-gnu");
787 triples.push_back("x86_64-unknown-linux-gnu");
788#elif defined(__i686__)
789 triples.push_back("i686-pc-linux-gnu");
790#elif defined(__i586__)
791 triples.push_back("i586-pc-linux-gnu");
792#elif defined(__i486__)
793 triples.push_back("i486-pc-linux-gnu");
794#elif defined(__i386__)
795 triples.push_back("i386-pc-linux-gnu");
796#elif defined(__arm__)
797 triples.push_back("armv8-none-linux-gnueabi");
798 triples.push_back("armv8-pc-linux-gnueabi");
799 triples.push_back("armv8-none-linux-gnu");
800 triples.push_back("armv8-pc-linux-gnu");
801 triples.push_back("armv7-none-linux-gnueabi");
802 triples.push_back("armv7-pc-linux-gnueabi");
803 triples.push_back("armv7-none-linux-gnu");
804 triples.push_back("armv7-pc-linux-gnu");
805 triples.push_back("armv6-none-linux-gnueabi");
806 triples.push_back("armv6-pc-linux-gnueabi");
807 triples.push_back("armv6-none-linux-gnu");
808 triples.push_back("armv6-pc-linux-gnu");
809#elif defined(__aarch64__)
810 triples.push_back("aarch64-none-linux-gnueabi");
811 triples.push_back("aarch64-pc-linux-gnueabi");
812 triples.push_back("aarch64-unknown-linux-gnueabi");
813 triples.push_back("aarch64-none-linux-gnu");
814 triples.push_back("aarch64-pc-linux-gnu");
815 triples.push_back("aarch64-unknown-linux-gnu");
816 triples.push_back("aarch64-redhat-linux");
817#endif
818
819 return triples;
820}
860static inline void populateIncludeDirs(std::vector<std::string>& args)
861{
862 auto sdk_location = locateSDKWithFallback();
863 auto& sdk = sdk_location.path;
864 auto qsdk = QString::fromStdString(sdk);
865
866 qDebug() << "SDK located: " << qsdk;
867 std::string llvm_lib_version = SCORE_LLVM_VERSION;
868#if defined(__APPLE__) && SCORE_FHS_BUILD
869 llvm_lib_version = "13.0.0";
870#endif
871
872 QDir resDir = QString(qsdk + "/lib/clang");
873 auto entries = resDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
874 if(!entries.empty() && !entries.contains(SCORE_LLVM_VERSION))
875 llvm_lib_version = entries.front().toStdString();
876
877#if defined(__APPLE__) && SCORE_FHS_BUILD
878 std::string appleSharedSdk
879 = "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/"
880 "usr";
881 args.push_back("-resource-dir");
882 args.push_back(appleSharedSdk + "/lib/clang/" + llvm_lib_version);
883#else
884 args.push_back("-resource-dir");
885 args.push_back(sdk + "/lib/clang/" + llvm_lib_version);
886#endif
887
888#if defined(_LIBCPP_VERSION)
889 args.push_back("-stdlib=libc++");
890 args.push_back("-internal-isystem");
891
892#if defined(__APPLE__) && SCORE_FHS_BUILD
893 args.push_back(appleSharedSdk + "/include/c++/v1");
894#else
895 args.push_back(sdk + "/include/c++/v1");
896#endif
897
898 // libc++'s per-target __config_site lives at include/<triple>/c++/v1 (multiarch
899 // layout) and is #include'd by the main libc++ headers, so that dir must also be
900 // on the search path.
901 {
902 const QDir incdir(qsdk + "/include");
903 for(const auto& d : incdir.entryList(QDir::Dirs | QDir::NoDotAndDotDot))
904 {
905 if(QFileInfo::exists(qsdk + "/include/" + d + "/c++/v1/__config_site"))
906 {
907 args.push_back("-internal-isystem");
908 args.push_back(sdk + "/include/" + d.toStdString() + "/c++/v1");
909 break;
910 }
911 }
912 }
913
914#elif defined(_GLIBCXX_RELEASE)
915 // Try to locate the correct libstdc++ folder
916 // TODO these are only heuristics. how to make them better ?
917 {
918 const auto libstdcpp_major = QString::number(_GLIBCXX_RELEASE);
919
920 QDir cpp_dir{"/usr/include/c++"};
921 // Note: as this is only used for debugging we look in the host /usr
922 QDirIterator cpp_it{cpp_dir};
923 while(cpp_it.hasNext())
924 {
925 cpp_it.next();
926 auto ver = cpp_it.fileName();
927 if(!ver.isEmpty() && ver.startsWith(libstdcpp_major))
928 {
929 auto gcc = ver.toStdString();
930
931 // e.g. /usr/include/c++/8.2.1
932 args.push_back("-internal-isystem");
933 args.push_back("/usr/include/c++/" + gcc);
934
935 cpp_dir.cd(ver);
936 for(auto& triple : getPotentialTriples())
937 {
938 if(cpp_dir.exists(triple))
939 {
940 // e.g. /usr/include/c++/8.2.1/x86_64-pc-linux-gnu
941 args.push_back("-internal-isystem");
942 args.push_back("/usr/include/c++/" + gcc + "/" + triple.toStdString());
943 break;
944 }
945 }
946
947 break;
948 }
949 }
950 }
951#endif
952
953#if defined(__APPLE__) && SCORE_FHS_BUILD
954 args.push_back("-internal-isystem");
955 args.push_back(appleSharedSdk + "/lib/clang/" + llvm_lib_version + "/include");
956 args.push_back("-internal-externc-isystem");
957 args.push_back(
958 "/Applications/Xcode.app/Contents/Developer//Platforms/MacOSX.platform/Developer/"
959 "SDKs/MacOSX.sdk/usr/include");
960#else
961 args.push_back("-internal-isystem");
962 args.push_back(sdk + "/lib/clang/" + llvm_lib_version + "/include");
963 args.push_back("-internal-externc-isystem");
964 args.push_back(sdk + "/include");
965#endif
966
967#if defined(__APPLE__)
968 // macOS framework headers are bundled flat in the SDK under include/macos-sdks
969 // (e.g. macos-sdks/ApplicationServices/ApplicationServices.h). In -cc1 mode no
970 // default framework path is added, so addons that transitively include a system
971 // framework (e.g. ApplicationServices via score/tools/Cursor.hpp) need this.
972 if(QFileInfo{qsdk + "/include/macos-sdks"}.isDir())
973 args.push_back("-isystem" + sdk + "/include/macos-sdks");
974#endif
975
976 // -resource-dir
977 // /opt/score-sdk/llvm/lib/clang/11.0.0
978 // -internal-isystem
979 // /opt/score-sdk/llvm/bin/../include/c++/v1
980 // -internal-isystem
981 // /opt/score-sdk/llvm/lib/clang/11.0.0/include
982 //-internal-externc-isystem
984
985 auto include = [&](const std::string& path) {
986 std::string path_to_include = sdk + "/include/" + path;
987 auto qpath = QString::fromStdString(path_to_include);
988 if(!QFileInfo{qpath}.isDir())
989 {
990 qDebug() << "Trying to include non-existent path: " << qpath;
991 }
992 else
993 {
994 args.push_back("-isystem" + sdk + "/include/" + path);
995 }
996 };
997
998#if defined(__linux__)
999// #debian
1000#if defined(__x86_64__)
1001 include("x86_64-linux-gnu");
1002#else
1003 include("aarch64-linux-gnu");
1004#endif
1005#endif
1006
1007 // include(""); // /usr/include
1008 std::string qt_folder = "qt";
1009 if(QFile::exists(qsdk + "/include/qt6/QtCore"))
1010 qt_folder = "qt6";
1011
1012 QDirIterator qtVersionFolder{
1013 qsdk + "/include/" + QString::fromStdString(qt_folder) + "/QtCore",
1014 {},
1015 QDir::Filter::Dirs | QDir::Filter::NoDotAndDotDot,
1016 {}};
1017 std::string qt_version = QT_VERSION_STR;
1018 if(qtVersionFolder.hasNext())
1019 {
1020 QDir sub = qtVersionFolder.next();
1021 qt_version = sub.dirName().toStdString();
1022 }
1023 include(qt_folder + "");
1024 include(qt_folder + "/QtCore");
1025 include(qt_folder + "/QtCore/" + qt_version);
1026 include(qt_folder + "/QtCore/" + qt_version + "/QtCore");
1027 include(qt_folder + "/QtGui");
1028 include(qt_folder + "/QtGui/" + qt_version);
1029 include(qt_folder + "/QtGui/" + qt_version + "/QtGui");
1030 include(qt_folder + "/QtWidgets");
1031 include(qt_folder + "/QtWidgets/" + qt_version);
1032 include(qt_folder + "/QtWidgets/" + qt_version + "/QtWidgets");
1033 include(qt_folder + "/QtQml");
1034 include(qt_folder + "/QtQml/" + qt_version);
1035 include(qt_folder + "/QtQml/" + qt_version + "/QtQml");
1036 include(qt_folder + "/QtQuick");
1037 include(qt_folder + "/QtQuick/" + qt_version);
1038 include(qt_folder + "/QtQuick/" + qt_version + "/QtQuick");
1039 include(qt_folder + "/QtXml");
1040 include(qt_folder + "/QtNetwork");
1041 include(qt_folder + "/QtSvg");
1042 include(qt_folder + "/QtSql");
1043 include(qt_folder + "/QtOpenGL");
1044 include(qt_folder + "/QtShaderTools");
1045 include(qt_folder + "/QtShaderTools/" + qt_version);
1046 include(qt_folder + "/QtShaderTools/" + qt_version + "/QtShaderTools");
1047 include(qt_folder + "/QtSerialPort");
1048
1049 if(sdk_location.sdk_kind == located_sdk::official && sdk_location.deploying)
1050 {
1051 include("score");
1052 }
1053 else
1054 {
1055 auto thirdparty_include_dirs = {
1056 "/3rdparty/libossia/3rdparty/boost_1_88_0",
1057 "/3rdparty/libossia/3rdparty/nano-signal-slot/include",
1058 "/3rdparty/libossia/3rdparty/spdlog/include",
1059 "/3rdparty/libossia/3rdparty/dr_libs",
1060 "/3rdparty/libossia/3rdparty/Flicks",
1061 "/3rdparty/libossia/3rdparty/fmt/include",
1062 "/3rdparty/libossia/3rdparty/magic_enum/include",
1063 "/3rdparty/libossia/3rdparty/readerwriterqueue",
1064 "/3rdparty/libossia/3rdparty/concurrentqueue",
1065 "/3rdparty/libossia/3rdparty/SmallFunction/smallfun/include",
1066 "/3rdparty/libossia/3rdparty/websocketpp",
1067 "/3rdparty/libossia/3rdparty/rapidjson/include",
1068 "/3rdparty/libossia/3rdparty/libremidi/include",
1069 "/3rdparty/libossia/3rdparty/oscpack",
1070 "/3rdparty/libossia/3rdparty/rnd/include",
1071 "/3rdparty/libossia/3rdparty/span/include",
1072 "/3rdparty/libossia/3rdparty/tuplet/include",
1073 "/3rdparty/libossia/3rdparty/unordered_dense/include",
1074 "/3rdparty/libossia/3rdparty/multi_index/include",
1075 "/3rdparty/libossia/3rdparty/verdigris/src",
1076 "/3rdparty/libossia/3rdparty/weakjack",
1077 };
1078 for(auto path : thirdparty_include_dirs)
1079 {
1080 args.push_back("-isystem" + std::string(SCORE_ROOT_SOURCE_DIR) + path);
1081 }
1082 auto src_include_dirs
1083 = {"/3rdparty/libossia/src",
1084 "/3rdparty/avendish/include",
1085 "/src/lib",
1086 "/src/plugins/score-lib-state",
1087 "/src/plugins/score-lib-device",
1088 "/src/plugins/score-lib-process",
1089 "/src/plugins/score-lib-inspector",
1090 "/src/plugins/score-plugin-avnd",
1091 "/src/plugins/score-plugin-gfx",
1092 "/src/plugins/score-plugin-jit",
1093 "/src/plugins/score-plugin-nodal",
1094 "/src/plugins/score-plugin-remotecontrol",
1095 "/src/plugins/score-plugin-audio",
1096 "/src/plugins/score-plugin-curve",
1097 "/src/plugins/score-plugin-dataflow",
1098 "/src/plugins/score-plugin-engine",
1099 "/src/plugins/score-plugin-scenario",
1100 "/src/plugins/score-plugin-library",
1101 "/src/plugins/score-plugin-deviceexplorer",
1102 "/src/plugins/score-plugin-media",
1103 "/src/plugins/score-plugin-loop",
1104 "/src/plugins/score-plugin-midi",
1105 "/src/plugins/score-plugin-protocols",
1106 "/src/plugins/score-plugin-recording",
1107 "/src/plugins/score-plugin-automation",
1108 "/src/plugins/score-plugin-js",
1109 "/src/plugins/score-plugin-mapping"};
1110
1111 for(auto path : src_include_dirs)
1112 {
1113 args.push_back("-I" + std::string(SCORE_ROOT_SOURCE_DIR) + path);
1114 }
1115
1116 auto src_build_dirs
1117 = {"/.",
1118 "/src/lib",
1119 "/src/plugins/score-lib-state",
1120 "/src/plugins/score-lib-device",
1121 "/src/plugins/score-lib-process",
1122 "/src/plugins/score-lib-inspector",
1123 "/src/plugins/score-plugin-avnd",
1124 "/src/plugins/score-plugin-gfx",
1125 "/src/plugins/score-plugin-jit",
1126 "/src/plugins/score-plugin-nodal",
1127 "/src/plugins/score-plugin-remotecontrol",
1128 "/src/plugins/score-plugin-audio",
1129 "/src/plugins/score-plugin-curve",
1130 "/src/plugins/score-plugin-dataflow",
1131 "/src/plugins/score-plugin-engine",
1132 "/src/plugins/score-plugin-scenario",
1133 "/src/plugins/score-plugin-library",
1134 "/src/plugins/score-plugin-deviceexplorer",
1135 "/src/plugins/score-plugin-media",
1136 "/src/plugins/score-plugin-loop",
1137 "/src/plugins/score-plugin-midi",
1138 "/src/plugins/score-plugin-protocols",
1139 "/src/plugins/score-plugin-recording",
1140 "/src/plugins/score-plugin-automation",
1141 "/src/plugins/score-plugin-js",
1142 "/src/plugins/score-plugin-mapping",
1143 "/3rdparty/libossia/src"};
1144
1145 for(auto path : src_build_dirs)
1146 {
1147 args.push_back("-I" + std::string(SCORE_ROOT_BINARY_DIR) + path);
1148 }
1149 }
1150}
1151
1152}
Definition LibrarySettings.hpp:46
Definition JitPlatform.hpp:129
T & settings() const
Access a specific Settings model instance.
Definition ApplicationContext.hpp:41