diff --git a/llvm/docs/CommandGuide/llvm-libtool-darwin.rst b/llvm/docs/CommandGuide/llvm-libtool-darwin.rst --- a/llvm/docs/CommandGuide/llvm-libtool-darwin.rst +++ b/llvm/docs/CommandGuide/llvm-libtool-darwin.rst @@ -38,6 +38,14 @@ Display the version of this program. +.. option:: -D + + Use zero for timestamps and UIDs/GIDs. This is set by default. + +.. option:: -U + + Use actual timestamps and UIDs/GIDs. + .. option:: -o Specify the output file name. Must be specified exactly once. diff --git a/llvm/test/tools/llvm-libtool-darwin/deterministic-library.test b/llvm/test/tools/llvm-libtool-darwin/deterministic-library.test new file mode 100644 --- /dev/null +++ b/llvm/test/tools/llvm-libtool-darwin/deterministic-library.test @@ -0,0 +1,42 @@ +## This test checks that timestamps/etc. are set to 0 by default or when -D +## option is specified. Timestamps/etc. are preserved when -U option is +## specified. +## We only test timestamps as a proxy for full deterministic writing; i.e. we +## assume UID/GIDs are preserved if timestamps are preserved. + +# RUN: yaml2obj %S/Inputs/input1.yaml -o %t-input1.o +# RUN: touch -t 199505050555.55 %t-input1.o + +## Test values are set to 0 (by default): +# RUN: llvm-libtool-darwin -static -o %t.lib %t-input1.o +# RUN: env TZ=GMT llvm-ar tv %t.lib | FileCheck %s --check-prefix=CHECK-DETERMINISTIC + +## Test values are set to 0 (with -D): +# RUN: llvm-libtool-darwin -static -o %t.lib -D %t-input1.o +# RUN: env TZ=GMT llvm-ar tv %t.lib | FileCheck %s --check-prefix=CHECK-DETERMINISTIC + +# CHECK-DETERMINISTIC: {{[[:space:]]1970[[:space:]]}} + +## Test values are preserved (with -U): +# RUN: llvm-libtool-darwin -static -o %t.lib -U %t-input1.o +# RUN: env TZ=GMT llvm-ar tv %t.lib | FileCheck %s --check-prefix=CHECK-NONDETERMINISTIC + +# CHECK-NONDETERMINISTIC: {{[[:space:]]1995[[:space:]]}} + +## D Flag specified more than once: +# RUN: not llvm-libtool-darwin -static -o %t.lib %t-input1.o -D -D 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CHECK-ERROR-D + +# CHECK-ERROR-D: for the -D option: may only occur zero or one times! + +## U Flag specified more than once: +# RUN: not llvm-libtool-darwin -static -o %t.lib %t-input1.o -U -U 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CHECK-ERROR-U + +# CHECK-ERROR-U: for the -U option: may only occur zero or one times! + +## Both D and U flags specified: +# RUN: not llvm-libtool-darwin -static -o %t.lib %t-input1.o -D -U 2>&1 | \ +# RUN: FileCheck %s --check-prefix=CHECK-ERROR-BOTH + +# CHECK-ERROR-BOTH: error: cannot specify both -D and -U flags diff --git a/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp b/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp --- a/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp +++ b/llvm/tools/llvm-libtool-darwin/llvm-libtool-darwin.cpp @@ -22,6 +22,8 @@ using namespace llvm; using namespace llvm::object; +static bool Deterministic; // Updated by 'D' and 'U' modifiers + cl::OptionCategory LibtoolCategory("llvm-libtool-darwin Options"); static cl::opt OutputFile("o", cl::desc("Specify output filename"), @@ -42,6 +44,14 @@ "Produce a statically linked library from the input files")), cl::Required, cl::cat(LibtoolCategory)); +static cl::opt DeterministicOption( + "D", cl::desc("Use zero for timestamps and UIDs/GIDs (Default)"), + cl::init(false), cl::cat(LibtoolCategory)); + +static cl::opt + NonDeterministicOption("U", cl::desc("Use actual timestamps and UIDs/GIDs"), + cl::init(false), cl::cat(LibtoolCategory)); + static cl::opt FileList("filelist", cl::desc("Pass in file containing a list of filenames"), @@ -101,7 +111,7 @@ static Error addChildMember(std::vector &Members, const object::Archive::Child &M) { Expected NMOrErr = - NewArchiveMember::getOldMember(M, /*Deterministic=*/true); + NewArchiveMember::getOldMember(M, Deterministic); if (!NMOrErr) return NMOrErr.takeError(); @@ -117,7 +127,7 @@ addMember(std::vector &Members, StringRef FileName, std::vector> &ArchiveBuffers) { Expected NMOrErr = - NewArchiveMember::getFile(FileName, /*Deterministic=*/true); + NewArchiveMember::getFile(FileName, Deterministic); if (!NMOrErr) return createFileError(FileName, NMOrErr.takeError()); @@ -163,27 +173,35 @@ if (Error E = writeArchive(OutputFile, NewMembers, /*WriteSymtab=*/true, - /*Kind=*/object::Archive::K_DARWIN, - /*Deterministic=*/true, + /*Kind=*/object::Archive::K_DARWIN, Deterministic, /*Thin=*/false)) return E; return Error::success(); } +static Error checkCommandLineOptions() { + if (DeterministicOption && NonDeterministicOption) + return createStringError(std::errc::invalid_argument, + "cannot specify both -D and -U flags"); + else + Deterministic = NonDeterministicOption ? false : true; + + if (!FileList.empty()) + if (Error E = processFileList()) + return E; + + if (InputFiles.empty()) + return createStringError(std::errc::invalid_argument, + "no input files specified"); + + return Error::success(); +} + int main(int Argc, char **Argv) { InitLLVM X(Argc, Argv); cl::HideUnrelatedOptions({&LibtoolCategory, &ColorCategory}); cl::ParseCommandLineOptions(Argc, Argv, "llvm-libtool-darwin\n"); - if (!FileList.empty()) { - if (Error E = processFileList()) { - WithColor::defaultErrorHandler(std::move(E)); - return EXIT_FAILURE; - } - } - - if (InputFiles.empty()) { - Error E = createStringError(std::errc::invalid_argument, - "no input files specified"); + if (Error E = checkCommandLineOptions()) { WithColor::defaultErrorHandler(std::move(E)); return EXIT_FAILURE; }