Compiling and Linking in Sandboxed app using LLVM binary

I am trying to build a sandboxed MacOSX app that can compile and link Objective C files.

I can succeed in doing this if sandboxing is turned off.
However, when sandboxing is turned on, the compiling works but linking fails with the error:
clang-9 xcrun: error: cannot be used within an App Sandbox.

I have downloaded the LLVM binary and created a Tools folder that contains the folders of the binary, namely bin, include, li, libexec, share.

My example app uses NSTask to call clang from Tools/bin/clang.
If you call clang from usr/bin/clang then sandboxing will not allow compilation.

I do not understand why compiling works but linking fails.
Is it possible to make the linking work within a sandboxed application?

My code follows.

Error Message:
2020-03-18 12:31:46.517403+0000 NewClangM21[799:13738] Compilation was successfull.
2020-03-18 12:31:46.585428+0000 NewClangM21[799:13738] There was a linking error: clang version 9.0.0 (git://github.com/llvm/llvm-project.git 0399d5a9682b3cef71c653373e38890c63c4c365)
Target: x86_64-apple-darwin18.7.0
Thread model: posix
InstalledDir: /Users/edmundfurse/Documents/NewClang/NewClangM21/DerivedData/NewClangM21/Build/Products/Debug/NewClangM21.app/Contents/Resources/Tools/bin
"/Applications/Xcode.app/Contents/Developer/usr/bin/ld" -demangle -lto_library /Users/edmundfurse/Documents/NewClang/NewClangM21/DerivedData/NewClangM21/Build/Products/Debug/NewClangM21.app/Contents/Resources/Tools/lib/libLTO.dylib -dynamic -arch x86_64 -bundle -macosx_version_min 10.14.0 -syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -o “/Users/edmundfurse/Library/Containers/com.uk.imitation.NewClangM21/Data/Library/Application Support/NewClangM21/ImitateScriptSystem/TemporaryFiles/TestMainTestMain” “/Users/edmundfurse/Library/Containers/com.uk.imitation.NewClangM21/Data/Library/Application Support/NewClangM21/ImitateScriptSystem/TemporaryFiles//TestMain.o” -framework Cocoa -framework Foundation -lSystem /Users/edmundfurse/Documents/NewClang/NewClangM21/DerivedData/NewClangM21/Build/Products/Debug/NewClangM21.app/Contents/Resources/Tools/lib/clang/9.0.0/lib/darwin/libclang_rt.osx.a "-F/Users/edmundfurse/Library/Containers/com.uk.imitation.NewClangM21/Data/Library/Application Support/NewClangM21/ImitateScriptSystem/TemporaryFiles/"
xcrun: error: cannot be used within an App Sandbox.
clang-9: error: linker command failed with exit code 1 (use -v to see invocation)
2020-03-18 12:31:46.586103+0000 NewClangM21[799:13738] CASE 1 LINK ERROR

//
// AppDelegate.m
// NewClangM21
//
// Created by Edmund Furse on 06/03/2020.
// Copyright © 2020 Imitation Ltd. All rights reserved.
//

#import “AppDelegate.h”
#import “NSFileManager+DirectoryLocations.h”

@interface AppDelegate ()

@property (weak) IBOutlet NSWindow *window;
@end

@implementation AppDelegate

  • (void)applicationDidFinishLaunching:(NSNotification )aNotification {
    // Insert code here to initialize your application
    NSString
    compileResult = [self compileScriptFile:@“TestMain”];
    if ([compileResult isEqualToString:@""])
    {
    NSLog(@“Compilation was successfull.”);
    }
    BOOL linkResult = [self linkScriptFiles:@“TestMain”];
    if (linkResult)
    {
    NSLog(@“Linking was successfull.”);
    }
    }

  • (void)applicationWillTerminate:(NSNotification *)aNotification {
    // Insert code here to tear down your application
    }

  • (NSString*)compileScriptFile:(NSString*)theScriptName
    {
    NSString applicationSupportDirectoryPath = [[NSFileManager defaultManager] applicationSupportDirectory];
    NSString
    temporaryFilesDirectoryName = concatenate(applicationSupportDirectoryPath, @"/ImitateScriptSystem/TemporaryFiles/");
    NSString* result = [self compileFile:theScriptName
    inDirectory:temporaryFilesDirectoryName
    toDirectory:temporaryFilesDirectoryName];
    if (![result isEqualToString:@""])
    {
    NSLog(@“There was an error compiling the file”);
    return result;
    }
    return @"";
    }

  • (NSString*)compileFile:(NSString*)fileName
    inDirectory:(NSString*)fromDirectoryPath
    toDirectory:(NSString*)toDirectoryPath
    // compiles the file using clang
    {
    NSTask* compileTask = [[NSTask alloc] init];
    NSString* clangPath = [[NSBundle mainBundle] pathForResource:@“clang” ofType:@"" inDirectory:@“Tools/bin/”];
    [compileTask setLaunchPath:clangPath];
    [compileTask setArguments:[NSArray arrayWithObjects:@"-c",concatenate3(fromDirectoryPath, fileName, @".m"),
    @"-isysroot",
    @"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk",
    @"-o",
    concatenate3(toDirectoryPath, fileName, @".o"),
    nil]];
    NSPipe* errorPipe = [[NSPipe alloc] init];
    NSFileHandle* errorReader = [errorPipe fileHandleForReading];
    [compileTask setStandardError:errorPipe];
    [compileTask launch];
    [compileTask waitUntilExit];
    NSString* errorString = [[NSString alloc] initWithData:[errorReader readDataToEndOfFile]
    encoding:NSUTF8StringEncoding];

if ([errorString length] != 0)
{
NSLog(@“There was a Compilation error: %@”, errorString);
return errorString;
}
return @"";
}

  • (BOOL)linkScriptFiles:(NSString*)theScriptName
    {
    NSString applicationSupportDirectoryPath = [[NSFileManager defaultManager] applicationSupportDirectory];
    NSString
    temporaryFilesDirectoryName = concatenate(applicationSupportDirectoryPath, @"/ImitateScriptSystem/TemporaryFiles/");

NSString* linkResult = [self linkTheScriptFilesToScriptName:theScriptName
intoDirectory:concatenate(temporaryFilesDirectoryName, theScriptName)];
if (![linkResult isEqualToString:@""])
{
if (searchOfString(@“error”, linkResult) != -1 || searchOfString(@“Error”, linkResult) != -1 || searchOfString(@“ERROR”, linkResult) != -1)
{
NSLog(@“CASE 1 LINK ERROR”);
return NO;
}
else if (searchOfString(@“warning”, linkResult) != -1 || searchOfString(@“Warning”, linkResult) != -1 || searchOfString(@“WARNING”, linkResult) != -1)
{
NSLog(@“CASE 2 LINK WARNING”);
return YES;
}
else
{
NSLog(@“CASE 3 UNKNOWN LINK PROBLEM”);
return NO;
}

}
return YES;
}

  • (NSString*)linkTheScriptFilesToScriptName:(NSString*)theScriptName intoDirectory:(NSString*)dir
    // links the file using clang
    {
    NSString applicationSupportDirectoryPath = [[NSFileManager defaultManager] applicationSupportDirectory];
    NSString
    temporaryFilesDirectoryName = concatenate(applicationSupportDirectoryPath, @"/ImitateScriptSystem/TemporaryFiles/");
    NSTask* linkTask = [[NSTask alloc] init];
    NSString* clangPath = [[NSBundle mainBundle] pathForResource:@“clang” ofType:@"" inDirectory:@“Tools/bin/”];
    [linkTask setLaunchPath:clangPath];
    [linkTask setArguments:[NSArray arrayWithObjects:
    concatenate4(temporaryFilesDirectoryName, @"/", theScriptName, @".o"),
    @"-framework",
    @“Cocoa”,
    @"-framework",
    @“Foundation”,
    concatenate(@"-F", temporaryFilesDirectoryName),
    @"-v",
    @"-isysroot",
    @"/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk",
    @"-bundle",
    @"-o",
    concatenate(dir, theScriptName),
    nil]];
    NSPipe* errorPipe = [[NSPipe alloc] init];
    NSFileHandle* errorReader = [errorPipe fileHandleForReading];
    [linkTask setStandardError:errorPipe];
    [linkTask launch];
    [linkTask waitUntilExit];
    NSString* errorString = [[NSString alloc] initWithData:[errorReader readDataToEndOfFile]
    encoding:NSUTF8StringEncoding];
    if ([errorString length] != 0)
    {
    NSLog(@“There was a linking error: %@”, errorString);
    if ((searchOfString(@“error”, errorString) != -1) ||
    (searchOfString(@“ERROR”, errorString) != -1))
    {
    return errorString;
    }
    else
    {
    return @""; // ALLOW WARNINGS.
    }
    return errorString;
    }
    return @"";
    }

NSString* concatenate(NSString* x, NSString* y)
{
if (!x && !y) return @"";
else if(!x) return y;
else if (!y) return x;
return [x stringByAppendingString:y];
}

NSString* concatenate3(NSString* x, NSString* y, NSString* z)
{
if (!x) x = @"";
if (!y) y = @"";
if (!z) z = @"";
return [[x stringByAppendingString:y] stringByAppendingString:z];
}

NSString* concatenate4(NSString* w, NSString* x, NSString* y, NSString* z)
{
if (!x) x = @"";
if (!y) y = @"";
if (!z) z = @"";
if (!w) w = @"";
return [[[w stringByAppendingString:x] stringByAppendingString:y] stringByAppendingString:z];
}

int searchOfString(NSString* x, NSString* str)
//searches for x within str, if not found returns -1
//otherwise returns its location.
{
if ((int)[str length] == 0) return -1;
if ((int)[x length] > (int)[str length]) return -1;
NSRange myRange = [str rangeOfString:x];
if (myRange.location != NSNotFound)
return (int)myRange.location;
else return -1;
}

@end

I am trying to build a sandboxed MacOSX app that can compile and link Objective C files.

I can succeed in doing this if sandboxing is turned off.
However, when sandboxing is turned on, the compiling works but linking fails with the error:
clang-9 xcrun: error: cannot be used within an App Sandbox.

I have downloaded the LLVM binary and created a Tools folder that contains the folders of the binary, namely bin, include, li, libexec, share.

My example app uses NSTask to call clang from Tools/bin/clang.
If you call clang from usr/bin/clang then sandboxing will not allow compilation.

I do not understand why compiling works but linking fails.

Because it tries to pull something from

-syslibroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk

?