This is going to be a quick post to explain a simple mistake that caused me a couple hours of confusion.
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))
"-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.
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
This solved the problem. The argument should be specified like so:
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.
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,
…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,
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:
- Understand that quotes are handled by the shell. System calls do nothing to your arguments
- CMake could have possibly validated its variables by checking for double quotes and erroring, saying "You probably don't mean