CodeCompass

Форк
0
/
ldlogger-tool-gcc.c 
262 строки · 5.6 Кб
1
#include <sys/types.h>
2
#include <stdint.h>
3
#include <stdlib.h>
4
#include <stdio.h>
5
#include <ctype.h>
6

7
#include "ldlogger-tool.h"
8
#include "ldlogger-util.h"
9

10
/**
11
 * States for GCCargument parser.
12
 */
13
typedef enum _GccArgsState
14
{
15
  /**
16
   * Normal state (default).
17
   */
18
  Normal,
19
  /**
20
   * After a -o paramater.
21
   */
22
  InOutputArg
23
} GccArgsState;
24

25
/**
26
 * List of file extensions accepted as source file.
27
 */
28
static const char* const srcExts[] = {
29
  "c", "cc", "cpp", "cxx", "h", "hh", "hxx", "hpp", "o", "so", "a", NULL
30
};
31

32
/**
33
 * Check if the given path is a gcc libpath or not.
34
 *
35
 * @param path_ an absolute directory path.
36
 * @return true if the given path is a gcc lib path, false if not.
37
 */
38
static int isGccLibPath(const char* path_)
39
{
40
  /* FIXME: it could be lib32 or lib64??? */
41
  const char* gccStart = strstr(path_, "/lib/gcc");
42
  if (!gccStart)
43
  {
44
    return 0;
45
  }
46

47
  /* We want to filter paths like:
48
   *   /usr/lib/gcc/x86_64-linux-gnu/4.8/include
49
   *   /usr/lib/gcc/x86_64-linux-gnu/4.8/include-fixed */
50
  return strstr(gccStart, "include") != NULL;
51
}
52

53
/**
54
 * Processes an command line argument for a GCC like command.
55
 *
56
 * @param state_ the current state of the parser.
57
 * @param arg_ the current command line argument.
58
 * @param action the current action.
59
 * @return the new state.
60
 */
61
static GccArgsState processArgument(
62
  GccArgsState state_,
63
  const char* arg_,
64
  LoggerAction* action_)
65
{
66
  char argToAdd[PATH_MAX];
67
  strcpy(argToAdd, arg_);
68

69
  if (state_ == InOutputArg)
70
  {
71
    if (!loggerMakePathAbs(arg_, argToAdd, 0))
72
    {
73
      strcpy(argToAdd, arg_);
74
    }
75

76
    loggerFileInitFromPath(&action_->output, argToAdd);
77
    state_ = Normal;
78
  }
79
  else if (strcmp(arg_, "-o") == 0)
80
  {
81
    state_ = InOutputArg;
82
  }
83
  else if (arg_[0] == '-' && (arg_[1] == 'I' || arg_[1] == 'L') && arg_[2])
84
  {
85
    /* This is a -I or -L option with a path */
86
    char fullPath[PATH_MAX];
87
    if (loggerMakePathAbs(arg_ + 2, fullPath, 0))
88
    {
89
      argToAdd[2] = 0;
90
      strcat(argToAdd, fullPath);
91
    }
92
  }
93
  else
94
  {
95
    char fullPath[PATH_MAX];
96
    if (loggerMakePathAbs(argToAdd, fullPath, 1))
97
    {
98
      char* ext = loggerGetFileExt(fullPath, 1);
99
      if (ext)
100
      {
101
        int i;
102
        for (i = 0; srcExts[i]; ++i)
103
        {
104
          if (strcmp(srcExts[i], ext) == 0)
105
          {
106
            strcpy(argToAdd, fullPath);
107
            loggerVectorAddUnique(&action_->sources,  loggerStrDup(fullPath),
108
              (LoggerCmpFuc) &strcmp);
109
            break;
110
          }
111
        }
112
      }
113

114
      free(ext);
115
    }
116
  }
117

118
  if (argToAdd[0])
119
  {
120
    loggerVectorAdd(&action_->arguments, loggerStrDup(argToAdd));
121
  }
122

123
  return state_;
124
}
125

126
/**
127
 * Tries to get the default header includes from a gcc(like) command and stores
128
 * the result into the given vector.
129
 *
130
 * @param prog_ the gcc like program / command.
131
 * @param args_ a vector for the arguments.
132
 */
133
static void getDefaultArguments(const char* prog_, LoggerVector* args_)
134
{
135
  char command[PATH_MAX];
136
  FILE* cmdOut;
137
  char* line = NULL;
138
  size_t lineSize = 0;
139
  ssize_t readSize;
140
  int incStarted = 0;
141

142
  strcpy(command, prog_);
143
  strcat(command, " -xc++ -E -v - < /dev/null 2>&1");
144

145
  cmdOut = popen(command, "r");
146
  if (!cmdOut)
147
  {
148
    return;
149
  }
150

151
  while ((readSize = getline(&line, &lineSize, cmdOut)) >= 0)
152
  {
153
    char fullPath[PATH_MAX] = "-I";
154
    char* pathEnd;
155
    char* pathStart;
156

157
    if (!incStarted)
158
    {
159
      if (strstr(line, "#include <...> search starts here"))
160
      {
161
        incStarted = 1;
162
      }
163
      continue;
164
    }
165
    else if (strstr(line, "End of search list"))
166
    {
167
      break;
168
    }
169

170
    /* Drop the new line character from the end of the line and the leading
171
       whitespaces. */
172
    for (pathStart = line; *pathStart && isspace(*pathStart); ++pathStart) {}
173
    for (pathEnd = pathStart; *pathEnd && !isspace(*pathEnd); ++pathEnd) {}
174
    *pathEnd = 0;
175
    if (pathStart[0] == 0)
176
    {
177
      /* WTF??? */
178
      continue;
179
    }
180

181
    if (!loggerMakePathAbs(pathStart, fullPath + 2, 0))
182
    {
183
      /* Invalid path, skip */
184
      continue;
185
    }
186

187
    if (isGccLibPath(fullPath))
188
    {
189
      /* We have to skip builtin gcc headers, we only need the paths to the
190
         stdlib */
191
      continue;
192
    }
193

194

195
    loggerVectorAdd(args_, loggerStrDup(fullPath));
196
  }
197

198
  free(line);
199
  pclose(cmdOut);
200
}
201

202
int loggerGccParserCollectActions(
203
  const char* prog_,
204
  const char* toolName_,
205
  const char* const argv_[],
206
  LoggerVector* actions_)
207
{
208
  size_t i;
209
  /* Position of the last include path + 1 */
210
  size_t lastIncPos = 1;
211
  GccArgsState state = Normal;
212
  LoggerAction* action = loggerActionNew(toolName_);
213

214
  loggerVectorAdd(&action->arguments, loggerStrDup(toolName_));
215

216
  for (i = 1; argv_[i]; ++i)
217
  {
218
    state = processArgument(state, argv_[i], action);
219
    if (argv_[i][0] == '-' && argv_[i][1] == 'I')
220
    {
221
      if (argv_[i][2])
222
      {
223
        /* -I with path argument */
224
        lastIncPos = action->arguments.size;
225
      }
226
      else
227
      {
228
        /* The path should be the next argument */
229
        lastIncPos = action->arguments.size + 1;
230
      }
231
    }
232
  }
233

234
  if (!getenv("CC_LOGGER_NO_DEF_DIRS"))
235
  {
236
    LoggerVector defIncludes;
237
    loggerVectorInit(&defIncludes);
238

239
    getDefaultArguments(prog_, &defIncludes);
240
    if (defIncludes.size)
241
    {
242
      loggerVectorAddFrom(&action->arguments, &defIncludes,
243
        &lastIncPos, (LoggerDupFuc) &loggerStrDup);
244
    }
245

246
    loggerVectorClear(&defIncludes);
247
  }
248

249
  /*
250
   * Workaround for -MT and friends: if the source set contains the output,
251
   * then we have to remove it from the set.
252
   */
253
  i = loggerVectorFind(&action->sources, action->output.path,
254
    (LoggerCmpFuc) &strcmp);
255
  if (i != SIZE_MAX)
256
  {
257
    loggerVectorErase(&action->sources, i);
258
  }
259

260
  loggerVectorAdd(actions_, action);
261
  return 1;
262
}
263

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.