[cmake-developers] Custom Command Escapes

Brad King brad.king at kitware.com
Wed Sep 27 16:08:16 EDT 2006


Hello, all:

I've been working on a fix for this bug:

http://www.cmake.org/Bug/bug.php?op=show&bugid=3786

This turns into a case where fixing a bug breaks code that works around
the bug already.  I'm looking for ideas on the best way to deal with
backwards-compatibility.

The problem is that the current generators do not treat command line
arguments to custom commands equally.  They use
cmSystemTools::EscapeSpaces to quote arguments when storing them in the
generated makefile or project file.  This is not sufficient when the
argument contains characters like

  '"$()&;\

and perhaps a few others.

For example the code

ADD_CUSTOM_TARGET(broken
  COMMAND some_exe
  c:/posix/path
  c:\\windows\\path
  'single-quotes'
  single'quote
  \"double-quotes\"
  double\"quote
  "semi;colon"
  \;semi-colons\;
  "(parens)"
  "(lparen"
  "rparen)"
  $dollar-signs$
  dollar$sign
  )

will produce a broken Makefile.  Just plain

ADD_CUSTOM_TARGET(broken COMMAND some_exe c:\\windows\\path)

will produce a working Makefile or VS project file but the path received
by the executable will be different on some platforms from that received
on others.  The reason is that the backslashes are not re-escaped
properly in the generated build system and thus may not be passed correctly.

As reported in the bug tracker there is now an implementation available
that generates the proper escapes for all build tools and shells.  I'd
like to enable use of this code, but it may break compatibility in a few
cases where people already tried to work around this bug.  For example:

ADD_CUSTOM_TARGET(some_target COMMAND some_exe -DVAR="'single-quotes'")

used to pass [-DVAR='single-quotes'] on all platforms but will now pass
[-DVAR="'single-quotes'"] using the new escape code.

Here are a few backwards compatibility suggestions:

1.) If CMAKE_BACKWARDS_COMPATIBILITY is lower than 2.5 or some other
version then use the old behavior.  Otherwise use the new escaping code.

pro: Converts everyone to the new correct behavior immediately
con: This is a user switch so a user could break the project by changing it.

2.) Add a VERBATIM argument to explicitly enable the new behavior:

ADD_CUSTOM_TARGET(some_target VERBATIM
  COMMAND some_exe -DVAR='single-quotes'
  )

pro: Completely compatible.  New syntax is needed to change behavior.
con: The correct behavior has ugly syntax compared to the old behavior.

3.) Add a variable like CMAKE_CUSTOM_ARGUMENTS_VERBATIM that when set to
true during a call to ADD_CUSTOM_* enables the behavior.

pro: Completely compatible.  The variable must be set by the project.
con: Choice of behavior is not obvious from just the invocation of
ADD_CUSTOM_*.  Also requires all projects to set this at the top when
they have been converted to the corrected behavior.

4.) Ignore the problem and make projects that want to support older
CMake versions switch their calls based on the cmake version.

pro: Fixes behavior for everyone immediately.  No work for us.
con: Not compatible with old projects.

The con can be partially fixed by adding a check for the variable
CMAKE_CUSTOM_ESCAPE_OLD_STYLE which users can add to the cache to build
old projects that have this problem.

5.) Other suggestions?

Note that the cases when working old behavior is changed by the new code
are rare.  The above single-quotes example was contrived.  The same
example with backslashes breaks with the old behavior.  Most working
code will continue to work because it does not need to work-around this
bug.  For this reason I'm tempted to choose #4.

Another issue is how to treat make variable syntax $(MAKEVAR) in custom
command arguments.  This syntax works in all the native build tools.  It
is useful on VS and Xcode to reference $(ConfigurationName) and
$(CONFIGURATION) respectively.  These are added by referencing
${CMAKE_CFG_INTDIR} in CMake code.

The new escaping code supports a switch to not escape these variable
references and allow the build tool to replace them.  My question here
is how to enable this option.  Should it be enabled by default?  Should
an extra argument to ADD_CUSTOM_* be needed to enable it or disable it?
 Note that this does not concern the command executable itself...only
the arguments need this escaping behavior.

-Brad


More information about the cmake-developers mailing list