]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
Send dependency arguments to compiler if run_second_cpp is true
authorJoel Rosdahl <joel@rosdahl.net>
Thu, 16 Jan 2020 20:04:09 +0000 (21:04 +0100)
committerJoel Rosdahl <joel@rosdahl.net>
Thu, 16 Jan 2020 20:04:09 +0000 (21:04 +0100)
If we run the compiler on the real source code on a cache miss (i.e.,
run_second_cpp is true) we can send the dependency arguments (-MD, etc.)
to the compiler instead of the preprocessor. When doing this there is no
need to add an implicit -MQ option to get the correct object file
location in the dependency file. Do so and also avoid adding an implicit
-MF option since that isn’t needed either. This should re-add support
for EDG-based compilers (see 6d453769 and #460).

If we run the compiler on the preprocessed source code on a cache miss
(i.e., run_second_cpp is false) we still need to let the preprocessor
generate the dependency file (the compiler doesn’t generate a dependency
file when compiling preprocessed source code) and thus we need to add
implicit -MQ and -MF.

This change reverts a fix (97b27781) for the Intel C++ compiler, but if
the Intel compiler still has problems the user can simply avoid setting
run_second_cpp to false.

src/ccache.cpp
test/suites/base.bash
test/suites/direct.bash
unittest/test_argument_processing.cpp

index f2dae5b2ad9018467007088963353bdfc2450b80..40be50a00c39194b222e9cbc85f965c95b61f902 100644 (file)
@@ -1805,13 +1805,16 @@ hash_common_info(struct args* args, struct hash* hash)
     }
   }
 
-  if (seen_split_dwarf) {
-    // When using -gsplit-dwarf, object files include a link to the
-    // corresponding .dwo file based on the target object filename, so we need
-    // to include the target filename in the hash to avoid handing out an
-    // object file with an incorrect .dwo link.
-    hash_delimiter(hash, "filename");
-    hash_string_view(hash, Util::base_name(output_obj));
+  if (generating_dependencies || seen_split_dwarf) {
+    // The output object file name is part of the .d file, so include the path
+    // in the hash if generating dependencies.
+    //
+    // Object files include a link to the corresponding .dwo file based on the
+    // target object filename when using -gsplit-dwarf, so hashing the object
+    // file path will do it, although just hashing the object file base name
+    // would be enough.
+    hash_delimiter(hash, "object file");
+    hash_string_view(hash, output_obj);
   }
 
   // Possibly hash the coverage data file path.
@@ -2172,12 +2175,6 @@ calculate_result_name(struct args* args,
       }
       args_pop(preprocessor_args, 1);
     }
-    if (generating_dependencies) {
-      // Nothing is actually created with -MF /dev/null
-      if (!str_eq(output_dep, "/dev/null")) {
-        cc_log("Preprocessor created %s", output_dep);
-      }
-    }
   }
 
   return result_name;
@@ -2208,10 +2205,8 @@ from_cache(enum fromcache_call_mode mode, bool put_result_in_manifest)
 
   MTR_BEGIN("cache", "from_cache");
 
-  // (If mode != FROMCACHE_DIRECT_MODE, the dependency file is created by gcc.)
-  bool produce_dep_file = generating_dependencies
-                          && mode == FROMCACHE_DIRECT_MODE
-                          && !str_eq(output_dep, "/dev/null");
+  bool produce_dep_file =
+    generating_dependencies && !str_eq(output_dep, "/dev/null");
 
   MTR_BEGIN("file", "file_get");
 
@@ -3424,17 +3419,25 @@ cc_process_args(struct args* args,
     }
   }
 
-  // Add flags for dependency generation only to the preprocessor command line.
   if (generating_dependencies) {
     if (!dependency_filename_specified) {
       std::string default_depfile_name =
         Util::change_extension(output_obj, ".d");
-      args_add(dep_args, "-MF");
-      args_add(dep_args, default_depfile_name.c_str());
       output_dep = make_relative_path(x_strdup(default_depfile_name.c_str()));
+      if (!g_config.run_second_cpp()) {
+        // If we're compiling preprocessed code we're sending dep_args to the
+        // preprocessor so we need to use -MF to write to the correct .d file
+        // location since the preprocessor doesn't know the final object path.
+        args_add(dep_args, "-MF");
+        args_add(dep_args, default_depfile_name.c_str());
+      }
     }
 
-    if (!dependency_target_specified && !dependency_implicit_target_specified) {
+    if (!dependency_target_specified && !dependency_implicit_target_specified
+        && !g_config.run_second_cpp()) {
+      // If we're compiling preprocessed code we're sending dep_args to the
+      // preprocessor so we need to use -MQ to get the correct target object
+      // file in the .d file.
       args_add(dep_args, "-MQ");
       args_add(dep_args, output_obj);
     }
@@ -3489,15 +3492,25 @@ cc_process_args(struct args* args,
     args_add(*compiler_args, arch_args[i]);
   }
 
-  // Only pass dependency arguments to the preprocessor since Intel's C++
-  // compiler doesn't produce a correct .d file when compiling preprocessed
-  // source.
-  args_extend(cpp_args, dep_args);
-
   *preprocessor_args = args_copy(common_args);
   args_extend(*preprocessor_args, cpp_args);
 
+  if (g_config.run_second_cpp()) {
+    // When not compiling the preprocessed source code, only pass dependency
+    // arguments to the compiler to avoid having to add -MQ, supporting e.g.
+    // EDG-based compilers which don't support -MQ.
+    args_extend(*compiler_args, dep_args);
+  } else {
+    // When compiling the preprocessed source code, pass dependency arguments to
+    // the preprocessor since the compiler doesn't produce a .d file when
+    // compiling preprocessed source code.
+    args_extend(*preprocessor_args, dep_args);
+  }
+
   *extra_args_to_hash = compiler_only_args;
+  if (g_config.run_second_cpp()) {
+    args_extend(*extra_args_to_hash, dep_args);
+  }
 
 out:
   args_free(expanded_args);
index a98952dec0aabdcc72e82ef15731dbc23741738c..4f5ea648e769ab98340e12faa2d36e4eacdf2cac 100644 (file)
@@ -1032,11 +1032,14 @@ EOF
     mkdir build
     cp test1.c build
 
+    i=0
     for src in test1.c build/test1.c; do
         for obj in test1.o build/test1.o; do
+            i=$((i + 1))
             $CCACHE_COMPILE -c -MMD $src -o $obj
             dep=$(echo $obj | sed 's/\.o$/.d/')
             expect_file_content $dep "$obj: $src"
+            expect_stat 'cache miss' $i
         done
     done
 
index 6acdde24a5422736dd399ff8f09cdc4c80844693..1d3a384dc7e3cf729eeb50d4233cfbdc918024df 100644 (file)
@@ -130,28 +130,43 @@ EOF
     # -------------------------------------------------------------------------
     TEST "Calculation of dependency file names"
 
-    mkdir test.dir
+    i=0
     for ext in .o .obj "" . .foo.bar; do
-        dep_file=test.dir/`echo test$ext | sed 's/\.[^.]*\$//'`.d
+        rm -rf testdir
+        mkdir testdir
 
-        $CCACHE_COMPILE -MD -c test.c -o test.dir/test$ext
+        dep_file=testdir/`echo test$ext | sed 's/\.[^.]*\$//'`.d
+
+        $CCACHE_COMPILE -MD -c test.c -o testdir/test$ext
+        expect_stat 'cache hit (direct)' $((2 * i))
+        expect_stat 'cache miss' $((2 * i + 1))
         rm -f $dep_file
-        $CCACHE_COMPILE -MD -c test.c -o test.dir/test$ext
+
+        $CCACHE_COMPILE -MD -c test.c -o testdir/test$ext
+        expect_stat 'cache hit (direct)' $((2 * i + 1))
+        expect_stat 'cache miss' $((2 * i + 1))
         expect_file_exists $dep_file
         if ! grep "test$ext:" $dep_file >/dev/null 2>&1; then
-            test_failed "$dep_file does not contain test$ext"
+            test_failed "$dep_file does not contain \"test$ext:\""
         fi
 
         dep_target=foo.bar
-        $CCACHE_COMPILE -MD -MQ $dep_target -c test.c -o test.dir/test$ext
+        $CCACHE_COMPILE -MD -MQ $dep_target -c test.c -o testdir/test$ext
+        expect_stat 'cache hit (direct)' $((2 * i + 1))
+        expect_stat 'cache miss' $((2 * i + 2))
         rm -f $dep_target
-        $CCACHE_COMPILE -MD -MQ $dep_target -c test.c -o test.dir/test$ext
+
+        $CCACHE_COMPILE -MD -MQ $dep_target -c test.c -o testdir/test$ext
+        expect_stat 'cache hit (direct)' $((2 * i + 2))
+        expect_stat 'cache miss' $((2 * i + 2))
         expect_file_exists $dep_file
         if ! grep $dep_target $dep_file >/dev/null 2>&1; then
             test_failed "$dep_file does not contain $dep_target"
         fi
+
+        i=$((i + 1))
     done
-    expect_stat 'files in cache' 12
+    expect_stat 'files in cache' $((4 * i))
 
     # -------------------------------------------------------------------------
     TEST "-MMD for different source files"
index 1efa8d6d55b8ed8f00cea3003cc6da70202500ed..9216555f7ac4d70cfc104cfb308332170ae78e99 100644 (file)
@@ -86,16 +86,42 @@ TEST(dash_M_should_be_unsupported)
   args_free(orig);
 }
 
-TEST(dependency_flags_should_only_be_sent_to_the_preprocessor)
+TEST(dependency_args_to_preprocessor_if_run_second_cpp_is_false)
 {
-#define CMD                                                                    \
-  "cc -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2"                  \
-  " -Wp,-MD,wpmd -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf"
-  struct args* orig = args_init_from_string(CMD " -c foo.c -o foo.o");
-  struct args* exp_cpp = args_init_from_string(CMD);
+#define DEP_ARGS                                                               \
+  "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd"        \
+  " -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf"
+  struct args* orig =
+    args_init_from_string("cc " DEP_ARGS " -c foo.c -o foo.o");
+  struct args* exp_cpp = args_init_from_string("cc " DEP_ARGS);
   struct args* exp_extra = args_init(0, NULL);
-#undef CMD
   struct args* exp_cc = args_init_from_string("cc -c");
+#undef DEP_ARGS
+  struct args* act_cpp = NULL;
+  struct args* act_extra = NULL;
+  struct args* act_cc = NULL;
+  create_file("foo.c", "");
+
+  g_config.set_run_second_cpp(false);
+  CHECK(cc_process_args(orig, &act_cpp, &act_extra, &act_cc));
+  CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+  CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
+  CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+  args_free(orig);
+}
+
+TEST(dependency_args_to_compiler_if_run_second_cpp_is_true)
+{
+#define DEP_ARGS                                                               \
+  "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd"        \
+  " -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf"
+  struct args* orig =
+    args_init_from_string("cc " DEP_ARGS " -c foo.c -o foo.o");
+  struct args* exp_cpp = args_init_from_string("cc");
+  struct args* exp_extra = args_init_from_string(DEP_ARGS);
+  struct args* exp_cc = args_init_from_string("cc -c " DEP_ARGS);
+#undef DEP_ARGS
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
@@ -109,21 +135,23 @@ TEST(dependency_flags_should_only_be_sent_to_the_preprocessor)
   args_free(orig);
 }
 
-TEST(cpp_only_flags_to_preprocessor_if_run_second_cpp_is_false)
+TEST(cpp_only_args_to_preprocessor_if_run_second_cpp_is_false)
 {
-#define CMD                                                                    \
-  "cc -I. -idirafter . -iframework. -imacros . -imultilib ."                   \
-  " -include test.h -include-pch test.pch -iprefix . -iquote ."                \
-  " -isysroot . -isystem . -iwithprefix . -iwithprefixbefore ."                \
-  " -DTEST_MACRO -DTEST_MACRO2=1 -F. -trigraphs -fworking-directory"           \
-  " -fno-working-directory -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2"             \
-  " -MQ mq1 -MQ mq2 -Wp,-MD,wpmd -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt"          \
-  " -Wp,-MQ,wpmq -Wp,-MF,wpf"
-  struct args* orig = args_init_from_string(CMD " -c foo.c -o foo.o");
-  struct args* exp_cpp = args_init_from_string(CMD);
+#define CPP_ARGS                                                               \
+  "-I. -idirafter . -iframework. -imacros . -imultilib . -include test.h"      \
+  " -include-pch test.pch -iprefix . -iquote . -isysroot . -isystem ."         \
+  " -iwithprefix . -iwithprefixbefore . -DTEST_MACRO -DTEST_MACRO2=1 -F."      \
+  " -trigraphs -fworking-directory -fno-working-directory"
+#define DEP_ARGS                                                               \
+  "-MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd"        \
+  " -Wp,-MMD,wpmmd -Wp,-MP -Wp,-MT,wpmt -Wp,-MQ,wpmq -Wp,-MF,wpf"
+  struct args* orig =
+    args_init_from_string("cc " CPP_ARGS " " DEP_ARGS " -c foo.c -o foo.o");
+  struct args* exp_cpp = args_init_from_string("cc " CPP_ARGS " " DEP_ARGS);
   struct args* exp_extra = args_init(0, NULL);
-#undef CMD
   struct args* exp_cc = args_init_from_string("cc -c");
+#undef DEP_ARGS
+#undef CPP_ARGS
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
@@ -138,28 +166,91 @@ TEST(cpp_only_flags_to_preprocessor_if_run_second_cpp_is_false)
   args_free(orig);
 }
 
-TEST(cpp_only_flags_to_preprocessor_and_compiler_if_run_second_cpp_is_true)
+TEST(cpp_only_args_to_preprocessor_and_compiler_if_run_second_cpp_is_true)
+{
+#define CPP_ARGS                                                               \
+  "-I. -idirafter . -iframework. -imacros . -imultilib . -include test.h"      \
+  " -include-pch test.pch -iprefix . -iquote . -isysroot . -isystem ."         \
+  " -iwithprefix . -iwithprefixbefore . -DTEST_MACRO -DTEST_MACRO2=1 -F."      \
+  " -trigraphs -fworking-directory -fno-working-directory"
+#define DEP_ARGS                                                               \
+  " -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 -MQ mq1 -MQ mq2 -Wp,-MD,wpmd"       \
+  " -Wp,-MMD,wpmmd"
+  struct args* orig =
+    args_init_from_string("cc " CPP_ARGS " " DEP_ARGS " -c foo.c -o foo.o");
+  struct args* exp_cpp = args_init_from_string("cc " CPP_ARGS);
+  struct args* exp_extra = args_init_from_string(DEP_ARGS);
+  struct args* exp_cc = args_init_from_string("cc " CPP_ARGS " -c " DEP_ARGS);
+#undef DEP_ARGS
+#undef CPP_ARGS
+  struct args* act_cpp = NULL;
+  struct args* act_extra = NULL;
+  struct args* act_cc = NULL;
+  create_file("foo.c", "");
+
+  CHECK(cc_process_args(orig, &act_cpp, &act_extra, &act_cc));
+  CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+  CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
+  CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+  args_free(orig);
+}
+
+TEST(dependency_args_that_take_an_argument_should_not_require_space_delimiter)
+{
+#define DEP_ARGS "-MMD -MFfoo.d -MT mt -MTmt -MQmq"
+  struct args* orig =
+    args_init_from_string("cc -c " DEP_ARGS " foo.c -o foo.o");
+  struct args* exp_cpp = args_init_from_string("cc");
+  struct args* exp_extra = args_init_from_string(DEP_ARGS);
+  struct args* exp_cc = args_init_from_string("cc -c " DEP_ARGS);
+#undef DEP_ARGS
+  struct args* act_cpp = NULL;
+  struct args* act_extra = NULL;
+  struct args* act_cc = NULL;
+  create_file("foo.c", "");
+
+  CHECK(cc_process_args(orig, &act_cpp, &act_extra, &act_cc));
+  CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+  CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
+  CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+  args_free(orig);
+}
+
+TEST(MQ_flag_should_not_be_added_if_run_second_cpp_is_true)
 {
-#define CMD                                                                    \
-  "cc -I. -idirafter . -iframework. -imacros . -imultilib ."                   \
-  " -include test.h -include-pch test.pch -iprefix . -iquote ."                \
-  " -isysroot . -isystem . -iwithprefix . -iwithprefixbefore ."                \
-  " -DTEST_MACRO -DTEST_MACRO2=1 -F. -trigraphs -fworking-directory"           \
-  " -fno-working-directory"
-#define DEP_OPTS                                                               \
-  " -MD -MMD -MP -MF foo.d -MT mt1 -MT mt2 "                                   \
-  " -MQ mq1 -MQ mq2 -Wp,-MD,wpmd -Wp,-MMD,wpmmd"
-  struct args* orig = args_init_from_string(CMD DEP_OPTS " -c foo.c -o foo.o");
-  struct args* exp_cpp = args_init_from_string(CMD DEP_OPTS);
+  struct args* orig =
+    args_init_from_string("cc -c -MD foo.c -MF foo.d -o foo.o");
+  struct args* exp_cpp = args_init_from_string("cc");
+  struct args* exp_extra = args_init_from_string("-MD -MF foo.d");
+  struct args* exp_cc = args_init_from_string("cc -c -MD -MF foo.d");
+  struct args* act_cpp = NULL;
+  struct args* act_extra = NULL;
+  struct args* act_cc = NULL;
+  create_file("foo.c", "");
+
+  CHECK(cc_process_args(orig, &act_cpp, &act_extra, &act_cc));
+  CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+  CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
+  CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+  args_free(orig);
+}
+
+TEST(MQ_flag_should_be_added_if_run_second_cpp_is_false)
+{
+  struct args* orig =
+    args_init_from_string("cc -c -MD foo.c -MF foo.d -o foo.o");
+  struct args* exp_cpp = args_init_from_string("cc -MD -MF foo.d -MQ foo.o");
   struct args* exp_extra = args_init(0, NULL);
-  struct args* exp_cc = args_init_from_string(CMD " -c");
-#undef CMD
+  struct args* exp_cc = args_init_from_string("cc -c");
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
   create_file("foo.c", "");
 
-  g_config.set_run_second_cpp(true);
+  g_config.set_run_second_cpp(false);
   CHECK(cc_process_args(orig, &act_cpp, &act_extra, &act_cc));
   CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
   CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
@@ -168,17 +259,37 @@ TEST(cpp_only_flags_to_preprocessor_and_compiler_if_run_second_cpp_is_true)
   args_free(orig);
 }
 
-TEST(dependency_flags_that_take_an_argument_should_not_require_space_delimiter)
+TEST(MF_should_be_added_if_run_second_cpp_is_false)
 {
-  struct args* orig = args_init_from_string(
-    "cc -c -MMD -MFfoo.d -MT mt -MTmt -MQmq foo.c -o foo.o");
-  struct args* exp_cpp =
-    args_init_from_string("cc -MMD -MFfoo.d -MT mt -MTmt -MQmq");
+  struct args* orig = args_init_from_string("cc -c -MD foo.c -o foo.o");
+  struct args* exp_cpp = args_init_from_string("cc -MD -MF foo.d -MQ foo.o");
   struct args* exp_extra = args_init(0, NULL);
   struct args* exp_cc = args_init_from_string("cc -c");
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
+
+  create_file("foo.c", "");
+
+  g_config.set_run_second_cpp(false);
+  CHECK(cc_process_args(orig, &act_cpp, &act_extra, &act_cc));
+  CHECK_ARGS_EQ_FREE12(exp_cpp, act_cpp);
+  CHECK_ARGS_EQ_FREE12(exp_extra, act_extra);
+  CHECK_ARGS_EQ_FREE12(exp_cc, act_cc);
+
+  args_free(orig);
+}
+
+TEST(MF_should_not_be_added_if_run_second_cpp_is_true)
+{
+  struct args* orig = args_init_from_string("cc -c -MD foo.c -o foo.o");
+  struct args* exp_cpp = args_init_from_string("cc");
+  struct args* exp_extra = args_init_from_string("-MD");
+  struct args* exp_cc = args_init_from_string("cc -c -MD");
+  struct args* act_cpp = NULL;
+  struct args* act_extra = NULL;
+  struct args* act_cc = NULL;
+
   create_file("foo.c", "");
 
   CHECK(cc_process_args(orig, &act_cpp, &act_extra, &act_cc));
@@ -192,9 +303,9 @@ TEST(dependency_flags_that_take_an_argument_should_not_require_space_delimiter)
 TEST(equal_sign_after_MF_should_be_removed)
 {
   struct args* orig = args_init_from_string("cc -c -MF=path foo.c -o foo.o");
-  struct args* exp_cpp = args_init_from_string("cc -MFpath");
-  struct args* exp_extra = args_init(0, NULL);
-  struct args* exp_cc = args_init_from_string("cc -c");
+  struct args* exp_cpp = args_init_from_string("cc");
+  struct args* exp_extra = args_init_from_string("-MFpath");
+  struct args* exp_cc = args_init_from_string("cc -c -MFpath");
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
@@ -262,9 +373,9 @@ TEST(MF_flag_with_immediate_argument_should_work_as_last_argument)
 {
   struct args* orig =
     args_init_from_string("cc -c foo.c -o foo.o -MMD -MT bar -MFfoo.d");
-  struct args* exp_cpp = args_init_from_string("cc -MMD -MT bar -MFfoo.d");
-  struct args* exp_extra = args_init(0, NULL);
-  struct args* exp_cc = args_init_from_string("cc -c");
+  struct args* exp_cpp = args_init_from_string("cc");
+  struct args* exp_extra = args_init_from_string("-MMD -MT bar -MFfoo.d");
+  struct args* exp_cc = args_init_from_string("cc -c -MMD -MT bar -MFfoo.d");
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
@@ -283,10 +394,11 @@ TEST(MT_flag_with_immediate_argument_should_work_as_last_argument)
 {
   struct args* orig =
     args_init_from_string("cc -c foo.c -o foo.o -MMD -MFfoo.d -MT foo -MTbar");
-  struct args* exp_cpp =
-    args_init_from_string("cc -MMD -MFfoo.d -MT foo -MTbar");
-  struct args* exp_extra = args_init(0, NULL);
-  struct args* exp_cc = args_init_from_string("cc -c");
+  struct args* exp_cpp = args_init_from_string("cc");
+  struct args* exp_extra =
+    args_init_from_string("-MMD -MFfoo.d -MT foo -MTbar");
+  struct args* exp_cc =
+    args_init_from_string("cc -c -MMD -MFfoo.d -MT foo -MTbar");
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
@@ -305,10 +417,11 @@ TEST(MQ_flag_with_immediate_argument_should_work_as_last_argument)
 {
   struct args* orig =
     args_init_from_string("cc -c foo.c -o foo.o -MMD -MFfoo.d -MQ foo -MQbar");
-  struct args* exp_cpp =
-    args_init_from_string("cc -MMD -MFfoo.d -MQ foo -MQbar");
-  struct args* exp_extra = args_init(0, NULL);
-  struct args* exp_cc = args_init_from_string("cc -c");
+  struct args* exp_cpp = args_init_from_string("cc");
+  struct args* exp_extra =
+    args_init_from_string("-MMD -MFfoo.d -MQ foo -MQbar");
+  struct args* exp_cc =
+    args_init_from_string("cc -c -MMD -MFfoo.d -MQ foo -MQbar");
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
@@ -327,10 +440,10 @@ TEST(MQ_flag_without_immediate_argument_should_not_add_MQobj)
 {
   struct args* orig =
     args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQ foo.d foo.c");
-  struct args* exp_cpp =
-    args_init_from_string("gcc -MD -MP -MFfoo.d -MQ foo.d");
-  struct args* exp_extra = args_init(0, NULL);
-  struct args* exp_cc = args_init_from_string("gcc -c");
+  struct args* exp_cpp = args_init_from_string("gcc");
+  struct args* exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MQ foo.d");
+  struct args* exp_cc =
+    args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQ foo.d");
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
@@ -349,10 +462,10 @@ TEST(MT_flag_without_immediate_argument_should_not_add_MTobj)
 {
   struct args* orig =
     args_init_from_string("gcc -c -MD -MP -MFfoo.d -MT foo.d foo.c");
-  struct args* exp_cpp =
-    args_init_from_string("gcc -MD -MP -MFfoo.d -MT foo.d");
-  struct args* exp_extra = args_init(0, NULL);
-  struct args* exp_cc = args_init_from_string("gcc -c");
+  struct args* exp_cpp = args_init_from_string("gcc");
+  struct args* exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MT foo.d");
+  struct args* exp_cc =
+    args_init_from_string("gcc -c -MD -MP -MFfoo.d -MT foo.d");
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
@@ -371,9 +484,10 @@ TEST(MQ_flag_with_immediate_argument_should_not_add_MQobj)
 {
   struct args* orig =
     args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQfoo.d foo.c");
-  struct args* exp_cpp = args_init_from_string("gcc -MD -MP -MFfoo.d -MQfoo.d");
-  struct args* exp_extra = args_init(0, NULL);
-  struct args* exp_cc = args_init_from_string("gcc -c");
+  struct args* exp_cpp = args_init_from_string("gcc");
+  struct args* exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MQfoo.d");
+  struct args* exp_cc =
+    args_init_from_string("gcc -c -MD -MP -MFfoo.d -MQfoo.d");
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;
@@ -392,9 +506,10 @@ TEST(MT_flag_with_immediate_argument_should_not_add_MQobj)
 {
   struct args* orig =
     args_init_from_string("gcc -c -MD -MP -MFfoo.d -MTfoo.d foo.c");
-  struct args* exp_cpp = args_init_from_string("gcc -MD -MP -MFfoo.d -MTfoo.d");
-  struct args* exp_extra = args_init(0, NULL);
-  struct args* exp_cc = args_init_from_string("gcc -c");
+  struct args* exp_cpp = args_init_from_string("gcc");
+  struct args* exp_extra = args_init_from_string("-MD -MP -MFfoo.d -MTfoo.d");
+  struct args* exp_cc =
+    args_init_from_string("gcc -c -MD -MP -MFfoo.d -MTfoo.d");
   struct args* act_cpp = NULL;
   struct args* act_extra = NULL;
   struct args* act_cc = NULL;