atilaneves / cmake-ide

Use Emacs as a C/C++ IDE
BSD 3-Clause "New" or "Revised" License
713 stars 92 forks source link

Doesn't properly parse defines with quotes #177

Open Colecf opened 5 years ago

Colecf commented 5 years ago

When trying to create a compiler definition called VERSION set to the string "1.0.0" (with the quotes), cmake-ide doesn't seem to parse it correctly. Here's an example that compiles fine, but gets flycheck errors constantly when trying to edit it in emacs:

CMakeLists.txt

cmake_minimum_required (VERSION 2.6)
cmake_policy(SET CMP0005 NEW)
add_definitions(-DVERSION="1.0.0")

add_executable(test test.cpp)

test.cpp

#include <stdio.h>

int main(int argc, char* argv[]) {
  printf("Version is %s\n", VERSION);
}

I get this for flycheck-clang-definitions:

flycheck-clang-definitions is a variable defined in `flycheck.el'.
Its value is ("VERSION=")

And running flycheck-compile gives me:

-*- mode: compilation; default-directory: "~/test/" -*-
Compilation started at Wed Sep  5 17:31:51

clang -fsyntax-only -fno-color-diagnostics -fno-caret-diagnostics -fno-diagnostics-show-option -iquote /home/cole/test/ -Wall -Wextra -DVERSION\= 1.0.0 -o CMakeFiles/test.dir/test.o -c -x c\+\+ - < /home/cole/test/test.cpp
clang: error: no such file or directory: '1.0.0'

Compilation exited abnormally with code 1 at Wed Sep  5 17:31:51
Colecf commented 5 years ago

The issue is fixed if you change split-string-and-unquote to split-string in cide--split-command, but I'm not sure what the implications are of doing this.

atilaneves commented 5 years ago

Thanks for the detailed report, I'll look into it.

atilaneves commented 5 years ago

After looking at this and trying to understand why the current implementation is as it is, it's because the command string in the compilation database has to be split into a list of arguments, because, unfortunately, that's what flycheck requires.

Normally, splitting on space is ok, but... as #142 shows, sometimes there's a file name with spaces in it e.g. foo - bar, and in that case the relevant JSON is:

{
    "command": "g++ something \"foo - bar\" darkside"
}

(Notice the escaped quotes around the name added by CMake)

Trying to split the command string with split-string yields '("g++" "something" "\"foo" "-" "bar\"" "darkside") - obviously not what we want. However, split-string-and-unquote yields '("g++" "something" "foo - bar" "darkside") - success!

But... that fails in your case because the quotes are explicit, and not because there were spaces inside. So now I need to write an elisp function that splits on spaces, except if one of the atoms is a quoted string with spaces inside, and only unquote if there are spaces. Neither split-string nor split-string-and-unquote will do. Sigh.

chodak166 commented 5 years ago

Im also suffering from this issue. Simple add_definitions(-DAPP_NAME_STR="MyAppName") results in clang: error: no such file or directory: 'MyAppName'. Different quoting and escaping is also not working on this one. One way around for small projects is to use "stringification" preprocessor macros. Thanks for your work!