diff --git a/lld/MachO/LTO.cpp b/lld/MachO/LTO.cpp --- a/lld/MachO/LTO.cpp +++ b/lld/MachO/LTO.cpp @@ -138,8 +138,22 @@ saveBuffer(buf[i], config->outputFile + Twine(i) + ".lto.o"); } - if (!config->ltoObjPath.empty()) - fs::create_directories(config->ltoObjPath); + // In ThinLTO mode, Clang passes a temporary directory in -object_path_lto, + // while the argument is a single file in FullLTO mode. + bool objPathIsDir = true; + if (!config->ltoObjPath.empty()) { + if (std::error_code ec = fs::create_directories(config->ltoObjPath)) + fatal("cannot create LTO object path " + config->ltoObjPath + ": " + + ec.message()); + + if (!fs::is_directory(config->ltoObjPath)) { + objPathIsDir = false; + unsigned objCount = + count_if(buf, [](const SmallString<0> &b) { return !b.empty(); }); + if (objCount > 1) + fatal("-object_path_lto must specify a directory when using ThinLTO"); + } + } std::vector ret; for (unsigned i = 0; i != maxTasks; ++i) { @@ -149,9 +163,10 @@ uint32_t modTime = 0; if (!config->ltoObjPath.empty()) { filePath = config->ltoObjPath; - path::append(filePath, Twine(i) + "." + - getArchitectureName(config->arch()) + - ".lto.o"); + if (objPathIsDir) + path::append(filePath, Twine(i) + "." + + getArchitectureName(config->arch()) + + ".lto.o"); saveBuffer(buf[i], filePath); modTime = getModTime(filePath); } diff --git a/lld/test/MachO/invalid/invalid-lto-object-path.ll b/lld/test/MachO/invalid/invalid-lto-object-path.ll new file mode 100644 --- /dev/null +++ b/lld/test/MachO/invalid/invalid-lto-object-path.ll @@ -0,0 +1,27 @@ +; REQUIRES: x86 + +;; Creating read-only directories with `chmod 400` isn't supported on Windows +; UNSUPPORTED: system-windows + +;; -object_path_lto specifies a directory that cannot be created +; RUN: rm -rf %t && mkdir %t && mkdir %t/dir +; RUN: chmod 400 %t/dir +; RUN: llvm-as %s -o %t/full.o +; RUN: not %lld %t/full.o -o /dev/null -object_path_lto %t/dir/dir2 2>&1 | FileCheck %s --check-prefix=READONLY -DDIR=%t/dir/dir2 + +; READONLY: error: cannot create LTO object path [[DIR]]: {{.*}} + +;; Multiple objects need to be created, but -object_path_lto doesn't point to a directory +; RUN: touch %t/out.o +; RUN: opt -module-summary %s -o %t/thin.o +; RUN: not %lld %t/full.o %t/thin.o -o /dev/null -object_path_lto %t/out.o 2>&1 | FileCheck %s --check-prefix=MULTIPLE + +; MULTIPLE: error: -object_path_lto must specify a directory when using ThinLTO + + +target triple = "x86_64-apple-macosx10.15.0" +target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" + +define void @main() { + ret void +} diff --git a/lld/test/MachO/lto-object-path.ll b/lld/test/MachO/lto-object-path.ll --- a/lld/test/MachO/lto-object-path.ll +++ b/lld/test/MachO/lto-object-path.ll @@ -8,16 +8,23 @@ ; RUN: llvm-nm -pa %t/test | FileCheck %s --check-prefixes CHECK,NOOBJPATH ; RUN: %lld %t/test.o -o %t/test -object_path_lto %t/lto-temps -; RUN: llvm-nm -pa %t/test | FileCheck %s --check-prefixes CHECK,OBJPATH -DDIR=%t/lto-temps +; RUN: llvm-nm -pa %t/test | FileCheck %s --check-prefixes CHECK,OBJPATH-DIR -DDIR=%t/lto-temps -; CHECK: 0000000000000000 - 00 0000 SO /tmp/test.cpp -; NOOBJPATH-NEXT: 0000000000000000 - 03 0001 OSO /tmp/lto.tmp +;; check that the object path can be an existing file +; RUN: touch %t/lto-tmp.o +; RUN: %lld %t/test.o -o %t/test -object_path_lto %t/lto-tmp.o +; RUN: llvm-nm -pa %t/test | FileCheck %s --check-prefixes CHECK,OBJPATH-FILE -DFILE=%t/lto-tmp.o + + +; CHECK: 0000000000000000 - 00 0000 SO /tmp/test.cpp +; NOOBJPATH-NEXT: 0000000000000000 - 03 0001 OSO /tmp/lto.tmp ;; check that modTime is nonzero when `-object_path_lto` is provided -; OBJPATH-NEXT: {{[0-9a-f]*[1-9a-f]+[0-9a-f]*}} - 03 0001 OSO [[DIR]]/0.x86_64.lto.o -; CHECK-NEXT: {{[0-9a-f]+}} - 01 0000 FUN _main -; CHECK-NEXT: 0000000000000001 - 00 0000 FUN -; CHECK-NEXT: 0000000000000000 - 01 0000 SO -; CHECK-NEXT: {{[0-9a-f]+}} T _main +; OBJPATH-DIR-NEXT: {{[0-9a-f]*[1-9a-f]+[0-9a-f]*}} - 03 0001 OSO [[DIR]]/0.x86_64.lto.o +; OBJPATH-FILE-NEXT: {{[0-9a-f]*[1-9a-f]+[0-9a-f]*}} - 03 0001 OSO [[FILE]] +; CHECK-NEXT: {{[0-9a-f]+}} - 01 0000 FUN _main +; CHECK-NEXT: 0000000000000001 - 00 0000 FUN +; CHECK-NEXT: 0000000000000000 - 01 0000 SO +; CHECK-NEXT: {{[0-9a-f]+}} T _main target triple = "x86_64-apple-macosx10.15.0" target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"