yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
ff96d5935
master
1// slang-gcc-compiler-util.cpp 2#include "slang-gcc-compiler-util.h" 3 4#include "../core/slang-char-util.h" 5#include "../core/slang-common.h" 6#include "../core/slang-io.h" 7#include "../core/slang-shared-library.h" 8#include "../core/slang-string-slice-pool.h" 9#include "../core/slang-string-util.h" 10#include "slang-artifact-desc-util.h" 11#include "slang-artifact-diagnostic-util.h" 12#include "slang-artifact-representation-impl.h" 13#include "slang-artifact-util.h" 14#include "slang-com-helper.h" 15 16namespace Slang 17{ 18 19static Index _findVersionEnd (const UnownedStringSlice & in ) 20{ 21Index numDots = 0 ; 22const Index len = in .getLength (); 23 24for (Index i = 0 ;i < len ;++ i ) 25 { 26const char c = in [i ]; 27if (CharUtil ::isDigit (c )) 28 { 29continue ; 30 } 31if (c == '.' ) 32 { 33if (numDots >=2 ) 34 { 35return i ; 36 } 37numDots ++ ; 38continue ; 39 } 40return i ; 41 } 42return len ; 43} 44 45/* static */ SlangResult GCCDownstreamCompilerUtil ::parseVersion ( 46const UnownedStringSlice & text , 47const UnownedStringSlice & prefix , 48DownstreamCompilerDesc & outDesc ) 49{ 50List < UnownedStringSlice > lines ; 51StringUtil ::calcLines (text ,lines ); 52 53for (auto line :lines ) 54 { 55Index prefixIndex = line .indexOf (prefix ); 56if (prefixIndex < 0 ) 57 { 58continue ; 59 } 60 61const UnownedStringSlice remainingSlice = 62UnownedStringSlice (line .begin ()+ prefixIndex + prefix .getLength (),line .end ()).trim (); 63 64const Index versionEndIndex = _findVersionEnd (remainingSlice ); 65if (versionEndIndex < 0 ) 66 { 67return SLANG_FAIL ; 68 } 69 70const UnownedStringSlice versionSlice ( 71remainingSlice .begin (), 72remainingSlice .begin ()+ versionEndIndex ); 73 74// Version is in format 0.0.0 75List < UnownedStringSlice > split ; 76StringUtil ::split (versionSlice ,'.' ,split ); 77List < Int > digits ; 78 79for (auto v :split ) 80 { 81Int version ; 82SLANG_RETURN_ON_FAIL (StringUtil ::parseInt (v ,version )); 83digits .add (version ); 84 } 85 86if (digits .getCount ()< 2 ) 87 { 88return SLANG_FAIL ; 89 } 90 91outDesc .version .set (int (digits [0 ]),int (digits [1 ])); 92return SLANG_OK ; 93 } 94 95return SLANG_FAIL ; 96} 97 98SlangResult GCCDownstreamCompilerUtil ::calcVersion ( 99const ExecutableLocation & exe , 100DownstreamCompilerDesc & outDesc ) 101{ 102CommandLine cmdLine ; 103cmdLine .setExecutableLocation (exe ); 104cmdLine .addArg ("-v" ); 105 106ExecuteResult exeRes ; 107SLANG_RETURN_ON_FAIL (ProcessUtil ::execute (cmdLine ,exeRes )); 108 109// Note we now have builds that add other words in front of the version 110// such as "Ubuntu clang version" 111const UnownedStringSlice prefixes []= { 112UnownedStringSlice ::fromLiteral ("clang version" ), 113UnownedStringSlice ::fromLiteral ("gcc version" ), 114UnownedStringSlice ::fromLiteral ("Apple LLVM version" ), 115UnownedStringSlice ::fromLiteral ("Apple metal version" ), 116 117 }; 118const SlangPassThrough types []= { 119SLANG_PASS_THROUGH_CLANG , 120SLANG_PASS_THROUGH_GCC , 121SLANG_PASS_THROUGH_CLANG , 122SLANG_PASS_THROUGH_METAL , 123 }; 124 125SLANG_COMPILE_TIME_ASSERT (SLANG_COUNT_OF (prefixes )== SLANG_COUNT_OF (types )); 126 127for (Index i = 0 ;i < SLANG_COUNT_OF (prefixes );++ i ) 128 { 129// Set the type 130outDesc .type = types [i ]; 131// Extract the version 132if (SLANG_SUCCEEDED ( 133parseVersion (exeRes .standardError .getUnownedSlice (),prefixes [i ],outDesc ))) 134 { 135return SLANG_OK ; 136 } 137 } 138 139return SLANG_FAIL ; 140} 141 142static SlangResult _parseSeverity ( 143const UnownedStringSlice & in , 144ArtifactDiagnostic ::Severity & outSeverity ) 145{ 146typedef ArtifactDiagnostic ::Severity Severity ; 147 148if (in == "error" || in == "fatal error" ) 149 { 150outSeverity = Severity ::Error ; 151 } 152else if (in == "warning" ) 153 { 154outSeverity = Severity ::Warning ; 155 } 156else if (in == "info" || in == "note" ) 157 { 158outSeverity = Severity ::Info ; 159 } 160else 161 { 162return SLANG_FAIL ; 163 } 164return SLANG_OK ; 165} 166 167namespace 168{// anonymous 169 170enum class LineParseResult 171{ 172Single ,///< It's a single line 173Start ,///< Line was the start of a message 174Continuation ,///< Not totally clear, add to previous line if nothing else hit 175Ignore ,///< Ignore the line 176}; 177 178}// namespace 179 180static SlangResult _parseGCCFamilyLine ( 181SliceAllocator & allocator , 182const UnownedStringSlice & line , 183LineParseResult & outLineParseResult , 184ArtifactDiagnostic & outDiagnostic ) 185{ 186typedef ArtifactDiagnostic Diagnostic ; 187typedef Diagnostic ::Severity Severity ; 188 189// Set to default case 190outLineParseResult = LineParseResult ::Ignore ; 191 192/* example error output from different scenarios */ 193 194/* 195tests/cpp-compiler/c-compile-error.c: In function 'int main(int, char**)': 196tests/cpp-compiler/c-compile-error.c:8:13: error: 'b' was not declared in this scope 197int a = b + c; 198^ 199tests/cpp-compiler/c-compile-error.c:8:17: error: 'c' was not declared in this scope 200int a = b + c; 201^ 202*/ 203 204/* /tmp/ccS0JCWe.o:c-compile-link-error.c:(.rdata$.refptr.thing[.refptr.thing]+0x0): undefined 205reference to `thing' collect2: error: ld returned 1 exit status*/ 206 207/* 208clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated 209[-Wdeprecated] Undefined symbols for architecture x86_64: 210"_thing", referenced from: 211_main in c-compile-link-error-a83ace.o 212ld: symbol(s) not found for architecture x86_64 213clang: error: linker command failed with exit code 1 (use -v to see invocation) */ 214 215/* /tmp/c-compile-link-error-ccf151.o: In function `main': 216c-compile-link-error.c:(.text+0x19): undefined reference to `thing' 217clang: error: linker command failed with exit code 1 (use -v to see invocation) 218*/ 219 220/* /tmp/c-compile-link-error-301c8c.o: In function `main': 221/home/travis/build/shader-slang/slang/tests/cpp-compiler/c-compile-link-error.c:10: undefined 222reference to `thing' clang-7: error: linker command failed with exit code 1 (use -v to see 223invocation)*/ 224 225/* /path/slang-cpp-prelude.h:4:10: fatal error: ../slang.h: No such file or directory 226#include "slang.h" 227^~~~~~~~~~~~ 228compilation terminated.*/ 229 230/* g++: error: unrecognized command line option ‘-std=c++14’ */ 231 232outDiagnostic .stage = Diagnostic ::Stage ::Compile ; 233 234List < UnownedStringSlice > split ; 235StringUtil ::split (line ,':' ,split ); 236 237// On windows we can have paths that are a: etc... if we detect this we can combine 0 - 1 to 238// be 1. 239if (split .getCount ()> 1 && split [0 ].getLength ()== 1 ) 240 { 241const char c = split [0 ][0 ]; 242if ((c >='a' && c <='z' )|| (c >='A' && c <='Z' )) 243 { 244// We'll assume it's a path 245UnownedStringSlice path (split [0 ].begin (),split [1 ].end ()); 246split .removeAt (0 ); 247split [0 ]= path ; 248 } 249 } 250 251if (split .getCount ()== 2 ) 252 { 253const auto split0 = split [0 ].trim (); 254if (split0 == UnownedStringSlice ::fromLiteral ("ld" )) 255 { 256// We'll ignore for now 257outDiagnostic .stage = Diagnostic ::Stage ::Link ; 258outDiagnostic .severity = Severity ::Info ; 259outDiagnostic .text = allocator .allocate (split [1 ].trim ()); 260outLineParseResult = LineParseResult ::Start ; 261return SLANG_OK ; 262 } 263 264if (SLANG_SUCCEEDED (_parseSeverity (split0 ,outDiagnostic .severity ))) 265 { 266// Command line errors can be just contain 'error:' etc. Can be seen on apple/clang 267outDiagnostic .stage = Diagnostic ::Stage ::Compile ; 268outDiagnostic .text = allocator .allocate (split [1 ].trim ()); 269outLineParseResult = LineParseResult ::Single ; 270return SLANG_OK ; 271 } 272 273outLineParseResult = LineParseResult ::Ignore ; 274return SLANG_OK ; 275 } 276else if (split .getCount ()== 3 ) 277 { 278const auto split0 = split [0 ].trim (); 279const auto split1 = split [1 ].trim (); 280const auto text = split [2 ].trim (); 281 282// Check for special handling for clang or metal 283if (split0 .startsWith (UnownedStringSlice ::fromLiteral ("clang" ))|| 284split0 .startsWith (UnownedStringSlice ::fromLiteral ("metal" ))|| 285split0 .startsWith (UnownedStringSlice ::fromLiteral ("Clang" ))|| 286split0 == UnownedStringSlice ::fromLiteral ("g++" )|| 287split0 == UnownedStringSlice ::fromLiteral ("gcc" )) 288 { 289// Extract the type 290SLANG_RETURN_ON_FAIL (_parseSeverity (split [1 ].trim (),outDiagnostic .severity )); 291 292if (text .startsWith ("linker command failed" )) 293 { 294outDiagnostic .stage = Diagnostic ::Stage ::Link ; 295 } 296 297outDiagnostic .text = allocator .allocate (text ); 298outLineParseResult = LineParseResult ::Start ; 299return SLANG_OK ; 300 } 301else if (split1 .startsWith ("(.text" )) 302 { 303// This is a little weak... but looks like it's a link error 304outDiagnostic .filePath = allocator .allocate (split [0 ]); 305outDiagnostic .severity = Severity ::Error ; 306outDiagnostic .stage = Diagnostic ::Stage ::Link ; 307outDiagnostic .text = allocator .allocate (text ); 308outLineParseResult = LineParseResult ::Single ; 309return SLANG_OK ; 310 } 311else if (text .startsWith ("ld returned" )) 312 { 313outDiagnostic .stage = ArtifactDiagnostic ::Stage ::Link ; 314SLANG_RETURN_ON_FAIL (_parseSeverity (split [1 ].trim (),outDiagnostic .severity )); 315outDiagnostic .text = allocator .allocate (line ); 316outLineParseResult = LineParseResult ::Single ; 317return SLANG_OK ; 318 } 319else if (text == "" ) 320 { 321// This is probably a prelude line, we'll just ignore it 322outLineParseResult = LineParseResult ::Ignore ; 323return SLANG_OK ; 324 } 325 } 326else if (split .getCount ()== 4 ) 327 { 328// Probably a link error, give the source line 329String ext = Path ::getPathExt (split [0 ]); 330 331// Maybe a bit fragile -> but probably okay for now 332if (ext != "o" && ext != "obj" ) 333 { 334outLineParseResult = LineParseResult ::Ignore ; 335return SLANG_OK ; 336 } 337else 338 { 339outDiagnostic .filePath = allocator .allocate (split [1 ]); 340outDiagnostic .location .line = 0 ; 341outDiagnostic .location .column = 0 ; 342outDiagnostic .severity = Diagnostic ::Severity ::Error ; 343outDiagnostic .stage = Diagnostic ::Stage ::Link ; 344outDiagnostic .text = allocator .allocate (split [3 ]); 345 346outLineParseResult = LineParseResult ::Start ; 347return SLANG_OK ; 348 } 349 } 350else if (split .getCount () >=5 ) 351 { 352// Probably a regular error line 353SLANG_RETURN_ON_FAIL (_parseSeverity (split [3 ].trim (),outDiagnostic .severity )); 354 355outDiagnostic .filePath = allocator .allocate (split [0 ]); 356SLANG_RETURN_ON_FAIL (StringUtil ::parseInt (split [1 ],outDiagnostic .location .line )); 357 358// Everything from 4 to the end is the error 359outDiagnostic .text = allocator .allocate (split [4 ].begin (),split .getLast ().end ()); 360 361outLineParseResult = LineParseResult ::Start ; 362return SLANG_OK ; 363 } 364 365// Assume it's a continuation 366outLineParseResult = LineParseResult ::Continuation ; 367return SLANG_OK ; 368} 369 370/* static */ SlangResult GCCDownstreamCompilerUtil ::parseOutput ( 371const ExecuteResult & exeRes , 372IArtifactDiagnostics * diagnostics ) 373{ 374LineParseResult prevLineResult = LineParseResult ::Ignore ; 375 376SliceAllocator allocator ; 377 378diagnostics -> reset (); 379diagnostics -> setRaw (SliceUtil ::asCharSlice (exeRes .standardError )); 380 381// We hold in workDiagnostics so as it is more convenient to append to the last with a 382// continuation also means we don't hold the allocations of building up continuations, just the 383// results when finally allocated at the end 384List < ArtifactDiagnostic > workDiagnostics ; 385 386for (auto line :LineParser (exeRes .standardError .getUnownedSlice ())) 387 { 388ArtifactDiagnostic diagnostic ; 389 390LineParseResult lineRes ; 391 392SLANG_RETURN_ON_FAIL (_parseGCCFamilyLine (allocator ,line ,lineRes ,diagnostic )); 393 394switch (lineRes ) 395 { 396case LineParseResult ::Start : 397 { 398// It's start of a new message 399workDiagnostics .add (diagnostic ); 400prevLineResult = LineParseResult ::Start ; 401break ; 402 } 403case LineParseResult ::Single : 404 { 405// It's a single message, without anything following 406workDiagnostics .add (diagnostic ); 407prevLineResult = LineParseResult ::Ignore ; 408break ; 409 } 410case LineParseResult ::Continuation : 411 { 412if (prevLineResult == LineParseResult ::Start || 413prevLineResult == LineParseResult ::Continuation ) 414 { 415if (workDiagnostics .getCount ()> 0 ) 416 { 417auto & last = workDiagnostics .getLast (); 418 419// TODO(JS): Note that this is somewhat wasteful as every time we append we 420// just allocate more memory to hold the result. If we had an allocator 421// dedicated to 'text' we could perhaps just append to the end of the last 422// allocation 423// 424// We are now in a continuation, add to the last 425StringBuilder buf ; 426buf .append (asStringSlice (last .text )); 427buf .append ("\n" ); 428buf .append (line ); 429 430last .text = allocator .allocate (buf ); 431 } 432prevLineResult = LineParseResult ::Continuation ; 433 } 434break ; 435 } 436case LineParseResult ::Ignore : 437 { 438prevLineResult = lineRes ; 439break ; 440 } 441default : 442return SLANG_FAIL ; 443 } 444 } 445 446for (const auto & diagnostic :workDiagnostics ) 447 { 448diagnostics -> add (diagnostic ); 449 } 450 451if (diagnostics -> hasOfAtLeastSeverity (ArtifactDiagnostic ::Severity ::Error )|| 452exeRes .resultCode != 0 ) 453 { 454diagnostics -> setResult (SLANG_FAIL ); 455 } 456 457return SLANG_OK ; 458} 459 460/* static */ SlangResult GCCDownstreamCompilerUtil ::calcCompileProducts ( 461const CompileOptions & options , 462ProductFlags flags , 463IOSFileArtifactRepresentation * lockFile , 464List < ComPtr < IArtifact >>& outArtifacts ) 465{ 466SLANG_ASSERT (options .modulePath .count ); 467 468outArtifacts .clear (); 469 470if (flags & ProductFlag ::Execution ) 471 { 472StringBuilder builder ; 473const auto desc = ArtifactDescUtil ::makeDescForCompileTarget (options .targetType ); 474SLANG_RETURN_ON_FAIL ( 475ArtifactDescUtil ::calcPathForDesc (desc ,asStringSlice (options .modulePath ),builder )); 476 477auto fileRep = OSFileArtifactRepresentation ::create ( 478IOSFileArtifactRepresentation ::Kind ::Owned , 479builder .getUnownedSlice (), 480lockFile ); 481auto artifact = ArtifactUtil ::createArtifact (desc ); 482artifact -> addRepresentation (fileRep ); 483 484outArtifacts .add (artifact ); 485 } 486 487return SLANG_OK ; 488} 489 490/* static */ SlangResult GCCDownstreamCompilerUtil ::calcArgs ( 491const CompileOptions & options , 492CommandLine & cmdLine ) 493{ 494SLANG_ASSERT (options .modulePath .count ); 495 496PlatformKind platformKind = (options .platform == PlatformKind ::Unknown ) 497 ?PlatformUtil ::getPlatformKind () 498 :options .platform ; 499 500const auto targetDesc = ArtifactDescUtil ::makeDescForCompileTarget (options .targetType ); 501 502if (options .sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP ) 503 { 504cmdLine .addArg ("-fvisibility=hidden" ); 505 506// C++17 since we share headers with slang itself (which uses c++17) 507cmdLine .addArg ("-std=c++17" ); 508 } 509 510if (targetDesc .payload == ArtifactDesc ::Payload ::MetalAIR ) 511 { 512cmdLine .addArg ("-std=metal3.1" ); 513 } 514 515// Our generated code very often casts between dissimilar types with the 516// knowledge that they have the same representation. This is strictly 517// speaking UB, and GCC 10+ is happy to take advantage of this, stop it. 518cmdLine .addArg ("-fno-strict-aliasing" ); 519 520// TODO(JS): Here we always set -m32 on x86. It could be argued it is only necessary when 521// creating a shared library but if we create an object file, we don't know what to choose 522// because we don't know what final usage is. It could also be argued that the platformKind 523// could define the actual desired target - but as it stands we only have a target of 'Linux' 524// (as opposed to Win32/64). Really it implies we need an arch enumeration too. 525// 526// For now we just make X86 binaries try and produce x86 compatible binaries as fixes the 527// immediate problems. 528#if SLANG_PROCESSOR_X86 529/* Used to specify the processor more broadly. For a x86 binary we need to make sure we build 530x86 builds even when on an x64 system. -m32 -m64*/ 531cmdLine .addArg ("-m32" ); 532#endif 533 534switch (options .optimizationLevel ) 535 { 536case OptimizationLevel ::None : 537 { 538// No optimization 539cmdLine .addArg ("-O0" ); 540break ; 541 } 542case OptimizationLevel ::Default : 543 { 544cmdLine .addArg ("-Os" ); 545break ; 546 } 547case OptimizationLevel ::High : 548 { 549cmdLine .addArg ("-O2" ); 550break ; 551 } 552case OptimizationLevel ::Maximal : 553 { 554cmdLine .addArg ("-O3" ); 555break ; 556 } 557default : 558break ; 559 } 560 561if (options .debugInfoType != DebugInfoType ::None ) 562 { 563cmdLine .addArg ("-g" ); 564 } 565 566if (options .flags & CompileOptions ::Flag ::Verbose ) 567 { 568cmdLine .addArg ("-v" ); 569 } 570 571switch (options .floatingPointMode ) 572 { 573case FloatingPointMode ::Default : 574break ; 575case FloatingPointMode ::Precise : 576 { 577// cmdLine.addArg("-fno-unsafe-math-optimizations"); 578break ; 579 } 580case FloatingPointMode ::Fast : 581 { 582// We could enable SSE with -mfpmath=sse 583// But that would only make sense on a x64/x86 type processor and only if that feature 584// is present (it is on all x64) 585cmdLine .addArg ("-ffast-math" ); 586break ; 587 } 588 } 589 590StringBuilder moduleFilePath ; 591SLANG_RETURN_ON_FAIL (ArtifactDescUtil ::calcPathForDesc ( 592targetDesc , 593asStringSlice (options .modulePath ), 594moduleFilePath )); 595 596cmdLine .addArg ("-o" ); 597cmdLine .addArg (moduleFilePath ); 598 599switch (options .targetType ) 600 { 601case SLANG_SHADER_SHARED_LIBRARY : 602case SLANG_HOST_SHARED_LIBRARY : 603 { 604// Shared library 605cmdLine .addArg ("-shared" ); 606 607if (PlatformUtil ::isFamily (PlatformFamily ::Unix ,platformKind )) 608 { 609// Position independent 610cmdLine .addArg ("-fPIC" ); 611 } 612break ; 613 } 614case SLANG_HOST_EXECUTABLE : 615 { 616cmdLine .addArg ("-rdynamic" ); 617break ; 618 } 619case SLANG_OBJECT_CODE : 620 { 621// Don't link, just produce object file 622cmdLine .addArg ("-c" ); 623break ; 624 } 625default : 626break ; 627 } 628 629// Add defines 630for (const auto & define :options .defines ) 631 { 632StringBuilder builder ; 633 634builder <<"-D" ; 635builder <<define .nameWithSig ; 636if (define .value .count ) 637 { 638builder <<"=" <<asStringSlice (define .value ); 639 } 640 641cmdLine .addArg (builder ); 642 } 643 644// Add includes 645for (const auto & include :options .includePaths ) 646 { 647cmdLine .addArg ("-I" ); 648cmdLine .addArg (asString (include )); 649 } 650 651// Link options 652if (0 )// && options.targetType != TargetType::Object) 653 { 654// linkOptions << "-Wl,"; 655// cmdLine.addArg(linkOptions); 656 } 657 658if (options .targetType == SLANG_SHADER_SHARED_LIBRARY ) 659 { 660if (!PlatformUtil ::isFamily (PlatformFamily ::Apple ,platformKind )) 661 { 662// On MacOS, this linker option is not supported. That's ok though in 663// so far as on MacOS it does report any unfound symbols without the option. 664 665// Linker flag to report any undefined symbols as a link error 666cmdLine .addArg ("-Wl,--no-undefined" ); 667 } 668 } 669 670// Files to compile, need to be on the file system. 671for (IArtifact * sourceArtifact :options .sourceArtifacts ) 672 { 673ComPtr < IOSFileArtifactRepresentation > fileRep ; 674 675// TODO(JS): 676// Do we want to keep the file on the file system? It's probably reasonable to do so. 677SLANG_RETURN_ON_FAIL (sourceArtifact -> requireFile (ArtifactKeep ::Yes ,fileRep .writeRef ())); 678cmdLine .addArg (fileRep -> getPath ()); 679 } 680 681// Add the library paths 682 683if (options .libraryPaths .count && (options .targetType == SLANG_HOST_EXECUTABLE )) 684 { 685if (PlatformUtil ::isFamily (PlatformFamily ::Apple ,platformKind )) 686cmdLine .addArg ("-Wl,-rpath,@loader_path,-rpath,@loader_path/../lib" ); 687else 688cmdLine .addArg ("-Wl,-rpath,$ORIGIN,-rpath,$ORIGIN/../lib" ); 689 } 690 691StringSlicePool libPathPool (StringSlicePool ::Style ::Default ); 692 693for (const auto & libPath :options .libraryPaths ) 694 { 695libPathPool .add (libPath ); 696 } 697 698// Artifacts might add library paths 699for (IArtifact * artifact :options .libraries ) 700 { 701const auto artifactDesc = artifact -> getDesc (); 702// If it's a library for CPU types, try and use it 703if (ArtifactDescUtil ::isCpuBinary (artifactDesc )&& 704artifactDesc .kind == ArtifactKind ::Library ) 705 { 706ComPtr < IOSFileArtifactRepresentation > fileRep ; 707 708// Get the name and path (can be empty) to the library 709SLANG_RETURN_ON_FAIL (artifact -> requireFile (ArtifactKeep ::Yes ,fileRep .writeRef ())); 710 711const UnownedStringSlice path (fileRep -> getPath ()); 712libPathPool .add (Path ::getParentDirectory (path )); 713 714cmdLine .addPrefixPathArg ( 715"-l" , 716ArtifactDescUtil ::getBaseNameFromPath (artifact -> getDesc (),path )); 717 } 718 } 719 720if (options .sourceLanguage == SLANG_SOURCE_LANGUAGE_CPP && 721 !PlatformUtil ::isFamily (PlatformFamily ::Windows ,platformKind )) 722 { 723// Make STD libs available 724cmdLine .addArg ("-lstdc++" ); 725// Make maths lib available 726cmdLine .addArg ("-lm" ); 727 } 728 729for (const auto & libPath :libPathPool .getAdded ()) 730 { 731// Note that any escaping of the path is handled in the ProcessUtil:: 732cmdLine .addArg ("-L" ); 733cmdLine .addArg (libPath ); 734cmdLine .addArg ("-F" ); 735cmdLine .addArg (libPath ); 736 } 737 738// Add compiler specific options from user. 739for (auto compilerSpecificArg :options .compilerSpecificArguments ) 740 { 741const char * const arg = compilerSpecificArg ; 742cmdLine .addArg (arg ); 743 } 744 745return SLANG_OK ; 746} 747 748/* static */ SlangResult GCCDownstreamCompilerUtil ::createCompiler ( 749const ExecutableLocation & exe , 750ComPtr < IDownstreamCompiler >& outCompiler ) 751{ 752DownstreamCompilerDesc desc ; 753SLANG_RETURN_ON_FAIL (GCCDownstreamCompilerUtil ::calcVersion (exe ,desc )); 754 755auto compiler = new GCCDownstreamCompiler (desc ); 756ComPtr < IDownstreamCompiler > compilerIntf (compiler ); 757compiler -> m_cmdLine .setExecutableLocation (exe ); 758 759outCompiler .swap (compilerIntf ); 760return SLANG_OK ; 761} 762 763/* static */ SlangResult GCCDownstreamCompilerUtil ::locateGCCCompilers ( 764const String & path , 765ISlangSharedLibraryLoader * loader , 766DownstreamCompilerSet * set ) 767{ 768SLANG_UNUSED (loader ); 769 770ComPtr < IDownstreamCompiler > compiler ; 771if (SLANG_SUCCEEDED (createCompiler (ExecutableLocation (path ,"g++" ),compiler ))) 772 { 773// A downstream compiler for Slang must currently support C++17 - such that 774// the prelude and generated code works. 775// 776// The first version of gcc that supports stable `-std=c++17` is 9.0 777// https://gcc.gnu.org/projects/cxx-status.html 778 779auto desc = compiler -> getDesc (); 780if (desc .version .m_major < 9 ) 781 { 782// If the version isn't 9 or higher, we don't add this version of the compiler. 783return SLANG_OK ; 784 } 785 786set -> addCompiler (compiler ); 787 } 788return SLANG_OK ; 789} 790 791/* static */ SlangResult GCCDownstreamCompilerUtil ::locateClangCompilers ( 792const String & path , 793ISlangSharedLibraryLoader * loader , 794DownstreamCompilerSet * set ) 795{ 796SLANG_UNUSED (loader ); 797 798ComPtr < IDownstreamCompiler > compiler ; 799if (SLANG_SUCCEEDED (createCompiler (ExecutableLocation (path ,"clang++" ),compiler ))) 800 { 801set -> addCompiler (compiler ); 802 } 803return SLANG_OK ; 804} 805 806}// namespace Slang