@@ -99,6 +99,40 @@ static std::string displayName(StringRef MainExecutablePath) {
9999 return Name;
100100}
101101
102+ StringRef
103+ swift::frontend::utils::escapeForMake (StringRef raw,
104+ llvm::SmallVectorImpl<char > &buffer) {
105+ buffer.clear ();
106+
107+ // The escaping rules for GNU make are complicated due to the various
108+ // subsitutions and use of the tab in the leading position for recipes.
109+ // Various symbols have significance in different contexts. It is not
110+ // possible to correctly quote all characters in Make (as of 3.7). Match
111+ // gcc and clang's behaviour for the escaping which covers only a subset of
112+ // characters.
113+ for (unsigned I = 0 , E = raw.size (); I != E; ++I) {
114+ switch (raw[I]) {
115+ case ' #' : // Handle '#' the broken GCC way
116+ buffer.push_back (' \\ ' );
117+ break ;
118+
119+ case ' ' :
120+ for (unsigned J = I; J && raw[J - 1 ] == ' \\ ' ; --J)
121+ buffer.push_back (' \\ ' );
122+ buffer.push_back (' \\ ' );
123+ break ;
124+
125+ case ' $' : // $ is escaped by $
126+ buffer.push_back (' $' );
127+ break ;
128+ }
129+ buffer.push_back (raw[I]);
130+ }
131+ buffer.push_back (' \0 ' );
132+
133+ return buffer.data ();
134+ }
135+
102136// / Emits a Make-style dependencies file.
103137static bool emitMakeDependenciesIfNeeded (DiagnosticEngine &diags,
104138 DependencyTracker *depTracker,
@@ -118,39 +152,21 @@ static bool emitMakeDependenciesIfNeeded(DiagnosticEngine &diags,
118152 return true ;
119153 }
120154
121- // Declare a helper for escaping file names for use in Makefiles.
122- llvm::SmallString<256 > pathBuf;
123- auto escape = [&](StringRef raw) -> StringRef {
124- pathBuf.clear ();
125-
126- static const char badChars[] = " $#:\n " ;
127- size_t prev = 0 ;
128- for (auto index = raw.find_first_of (badChars); index != StringRef::npos;
129- index = raw.find_first_of (badChars, index+1 )) {
130- pathBuf.append (raw.slice (prev, index));
131- if (raw[index] == ' $' )
132- pathBuf.push_back (' $' );
133- else
134- pathBuf.push_back (' \\ ' );
135- prev = index;
136- }
137- pathBuf.append (raw.substr (prev));
138- return pathBuf;
139- };
155+ llvm::SmallString<256 > buffer;
140156
141157 // FIXME: Xcode can't currently handle multiple targets in a single
142158 // dependency line.
143159 opts.forAllOutputPaths (input, [&](const StringRef targetName) {
144- out << escape (targetName) << " :" ;
160+ out << swift::frontend::utils::escapeForMake (targetName, buffer ) << " :" ;
145161 // First include all other files in the module. Make-style dependencies
146162 // need to be conservative!
147163 for (auto const &path :
148164 reversePathSortedFilenames (opts.InputsAndOutputs .getInputFilenames ()))
149- out << ' ' << escape (path);
165+ out << ' ' << swift::frontend::utils::escapeForMake (path, buffer );
150166 // Then print dependencies we've picked up during compilation.
151167 for (auto const &path :
152168 reversePathSortedFilenames (depTracker->getDependencies ()))
153- out << ' ' << escape (path);
169+ out << ' ' << swift::frontend::utils::escapeForMake (path, buffer );
154170 out << ' \n ' ;
155171 });
156172
0 commit comments