Add support for the source_version cmdline option.

This is of the form A.B.C.D.E and to match ld64's behaviour, is
always output to files, even when the version is 0.

rdar://problem/24472630

llvm-svn: 259746
diff --git a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
index c758612..5e7db8f 100644
--- a/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachOLinkingContext.cpp
@@ -76,6 +76,35 @@
   return false;
 }
 
+bool MachOLinkingContext::parsePackedVersion(StringRef str, uint64_t &result) {
+  result = 0;
+
+  if (str.empty())
+    return false;
+
+  SmallVector<StringRef, 5> parts;
+  llvm::SplitString(str, parts, ".");
+
+  uint64_t num;
+  if (llvm::getAsUnsignedInteger(parts[0], 10, num))
+    return true;
+  if (num > 0xFFFFFF)
+    return true;
+  result = num << 40;
+
+  unsigned Shift = 30;
+  for (StringRef str : llvm::makeArrayRef(parts).slice(1)) {
+    if (llvm::getAsUnsignedInteger(str, 10, num))
+      return true;
+    if (num > 0x3FF)
+      return true;
+    result |= (num << Shift);
+    Shift -= 10;
+  }
+
+  return false;
+}
+
 MachOLinkingContext::ArchInfo MachOLinkingContext::_s_archInfos[] = {
   { "x86_64", arch_x86_64, true,  CPU_TYPE_X86_64,  CPU_SUBTYPE_X86_64_ALL },
   { "i386",   arch_x86,    true,  CPU_TYPE_I386,    CPU_SUBTYPE_X86_ALL },
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
index 0eb2b11..4e303dd 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileBinaryWriter.cpp
@@ -467,6 +467,10 @@
     ++count;
   }
 
+  // Add LC_SOURCE_VERSION
+  size += sizeof(source_version_command);
+  ++count;
+
   // If main executable add LC_MAIN
   if (_file.fileType == llvm::MachO::MH_EXECUTE) {
     size += sizeof(entry_point_command);
@@ -915,6 +919,17 @@
     // LC_VERSION_MIN_TVOS
     writeVersionMinLoadCommand(_file, _swap, lc);
 
+    // Add LC_SOURCE_VERSION
+    {
+      source_version_command* sv = reinterpret_cast<source_version_command*>(lc);
+      sv->cmd       = LC_SOURCE_VERSION;
+      sv->cmdsize   = sizeof(source_version_command);
+      sv->version   = _file.sourceVersion;
+      if (_swap)
+        swapStruct(*sv);
+      lc += sizeof(source_version_command);
+    }
+
     // If main executable, add LC_MAIN.
     if (_file.fileType == llvm::MachO::MH_EXECUTE) {
       // Build LC_MAIN load command.
diff --git a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
index c7fd2ca..6ac567b 100644
--- a/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
+++ b/lld/lib/ReaderWriter/MachO/MachONormalizedFileFromAtoms.cpp
@@ -1285,6 +1285,7 @@
   normFile.minOSVersionKind = util.minVersionCommandType();
 
   normFile.sdkVersion = context.sdkVersion();
+  normFile.sourceVersion = context.sourceVersion();
 
   if (context.generateVersionLoadCommand() &&
       context.os() != MachOLinkingContext::OS::unknown)