Linux execvp() and double quotes

By Macoy Madson. Published on .

This is going to be a quick post to explain a simple mistake that caused me a couple hours of confusion.

The Problem

From my recent post, you may know I have been working on a programming language, Cakelisp. I recently added the ability to easily run arbitrary processes in build hooks. This is so that GameLib can build its third party dependencies (SDL and Ogre) during pre-build rather than requiring the user to run a separate BuildDependencies.sh script. This ability opens the door for lots of other fun things, like cloning code and such.

This feature uses the same code Cakelisp uses to run the compiler, linker, etc., which is in RunProcess.cpp. On Linux, execvp() is used to start the process requested by the build script.

I successfully used this functionality to build SDL during a build hook. However, when I tried to port Ogre, I kept having problems with the Debug configuration not working. Here's what the build hook code looked like:

(run-process-make-arguments cmake-command "cmake"
                                 "-D" "OGRE_USE_BOOST=0"
                                 "-D" "OGRE_CONFIG_THREAD_PROVIDER=0"
                                 "-D" "OGRE_CONFIG_THREADS=0"
                                 "-D" "OGRE_BUILD_COMPONENT_SCENE_FORMAT=1"
                                 "-D" "OGRE_BUILD_SAMPLES2=1"
                                 "-D" "OGRE_BUILD_TESTS=1"
                                 "-D" "CMAKE_BUILD_TYPE=\"Debug\""
                                 "-G" "Ninja"
                                 "../.."
                                 :in-directory ogre-debug-output-dir)
(unless (= 0 (run-process-wait-for-completion (addr cmake-command)))
       (build-ogre-on-failure "failed at Ogre cmake. This tool requires CMake.")
       (return false))

Despite the "-D" "CMAKE_BUILD_TYPE=\"Debug\"" , the build type was not being set to Debug. I had copied that line straight from my BuildDependencies.sh, so I expected it to work.

The Solution

After trying a few different ways to specify Debug as well as trying the commands in different environments, I finally tried removing the quotes around Debug in the CMAKE_BUILD_TYPE argument.

This solved the problem. The argument should be specified like so:

"-D" "CMAKE_BUILD_TYPE=Debug"

What if we needed to specify a path with a space in it? That's fine, because my RunProcess code still puts that path in one arg, i.e. the same char* that the program will receive.

Explanation

In the shell, double quotes ( "" ) are handled by the shell, not by the underlying system exec() call. The shell interprets these quotes such that their contents are put into a single argument (a single char* passed to e.g. int main() second argument, argv ). As far as I can tell, the shell also combines those contents with preceding (and likely following) characters, as long as there is no space delimiting them.

So, in this case,

"-D" "CMAKE_BUILD_TYPE=\"Debug\""

…when called from exec(), CMake would receive a string CMAKE_BUILD_TYPE="Debug" . CMake then populates the CMAKE_BUILD_TYPE variable with the string "Debug" , not what we actually want, Debug .

When called from the shell, CMake receives CMAKE_BUILD_TYPE=Debug , which it properly interprets.

Because we are already providing exec() with separate pointers per argument, we don't need to worry about quoting anything with spaces.

Lessons I learned from this: