Generated Makefile build command gives errors as it has quotes in the build command

Hi,

I have created a CMakeLists.txt for cross compiling my C project. I have enabled many warning options and need many -D options as well. While adding these to target_compile_options() I have added quotes to make it like a string with spaces (also to avoid ‘;’ semi-colon).

I have also specified my arm-gcc compiler which is in a different path. The generated makefile has the settings the way I need.

My problem is that when generating makefile, it is adding quotes to the build command and bash gives an error command not found because of the quotes.

So for example the final make build command should be (without quotes):

/opt/gnu/arm-gcc -flag1 -flag2 -flag3 -option1 -option2 -option3 -o file.o -c file.c

but the generated command looks like (with quotes):

"/opt/gnu/arm-gcc -flag1 -flag2 -flag3" "-option1 -option2 -option3" -o file.o -c file.c

The above quotes gives errors (The quotes are balanced). I ran the generated command without quotes and it worked.

Any inputs on how I can solve this problem.

Thanks in advance!

You’ve shown us the results, but not the CMake logic you used to create them. Without that, it’s hard to say what’s really happening or offer advice on how to achieve what you want. Please put together a minimal, complete example that demonstrates your problem.

Here’s a minimal example that gives the problem:

cmake_minimum_required(VERSION 3.22.0)
project(test VERSION 1.0)

######### CROSS Compiling options

set(CMAKE_SYSTEM_PROCESSOR arm)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR "CUSTOM")
set(CMAKE_FIND_ROOT_PATH /opt/arm-gnu-toolchain/)
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

set(target_triple "arm-none-eabi")
set(toolchain_dir "/opt/arm-gnu-toolchain/bin")
set(cpu_flags "-mcpu=cortex-m7 -mthumb")
set(compiler_flags "${cpu_flags} -specs=nano.specs -specs=nosys.specs")

set(CMAKE_C_COMPILER "${toolchain_dir}/${target_triple}-gcc ${compiler_flags}")
set(CMAKE_SIZE ${target_triple}-size)
set(CMAKE_SYSROOT "/opt/arm-gnu-toolchain/arm-none-eabi/lib/")
set(CMAKE_EXECUTABLE_SUFFIX_C ".elf")

######### Project Specific options
set(project_macros "-DMACRO1 -DMACRO2")
set(common_warnings "-Wall -Wextra -Werror")
set(extra_warnings "-Wfatal-errors")

add_executable(test main.c)
target_compile_options(test PRIVATE "${compiler_flags} ${common_warnings} ${extra_warnings}")

my C file:

// main.c
#include <stdio.h>

int main(void)
{
	return 0;
}

The build output:

prasant@LenTP:/mnt/d/dev/test/build$ rm -rf * && cmake .. && make VERBOSE=1 all

-- The C compiler identification is GNU 11.4.0
-- The CXX compiler identification is GNU 11.4.0
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Check for working C compiler: /usr/bin/cc - skipped
-- Detecting C compile features
-- Detecting C compile features - done
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /mnt/d/dev/test/build

/usr/bin/cmake -S/mnt/d/dev/test -B/mnt/d/dev/test/build --check-build-system CMakeFiles/Makefile.cmake 0
/usr/bin/cmake -E cmake_progress_start /mnt/d/dev/test/build/CMakeFiles /mnt/d/dev/test/build//CMakeFiles/progress.marks
make  -f CMakeFiles/Makefile2 all
make[1]: Entering directory '/mnt/d/dev/test/build'
make  -f CMakeFiles/test.dir/build.make CMakeFiles/test.dir/depend
make[2]: Entering directory '/mnt/d/dev/test/build'
cd /mnt/d/dev/test/build && /usr/bin/cmake -E cmake_depends "Unix Makefiles" /mnt/d/dev/test /mnt/d/dev/test /mnt/d/dev/test/build /mnt/d/dev/test/build /mnt/d/dev/test/build/CMakeFiles/test.dir/DependInfo.cmake --color=
make[2]: Leaving directory '/mnt/d/dev/test/build'
make  -f CMakeFiles/test.dir/build.make CMakeFiles/test.dir/build
make[2]: Entering directory '/mnt/d/dev/test/build'
[ 50%] Building C object CMakeFiles/test.dir/main.c.o
"/opt/arm-gnu-toolchain/bin/arm-none-eabi-gcc -mcpu=cortex-m7 -mthumb -specs=nano.specs -specs=nosys.specs" --sysroot=/opt/arm-gnu-toolchain/arm-none-eabi/lib/   "-mcpu=cortex-m7 -mthumb -specs=nano.specs -specs=nosys.specs -Wall -Wextra -Werror -Wfatal-errors" -MD -MT CMakeFiles/test.dir/main.c.o -MF CMakeFiles/test.dir/main.c.o.d -o CMakeFiles/test.dir/main.c.o -c /mnt/d/dev/test/main.c
/bin/sh: 1: /opt/arm-gnu-toolchain/bin/arm-none-eabi-gcc -mcpu=cortex-m7 -mthumb -specs=nano.specs -specs=nosys.specs: not found
make[2]: *** [CMakeFiles/test.dir/build.make:76: CMakeFiles/test.dir/main.c.o] Error 127
make[2]: Leaving directory '/mnt/d/dev/test/build'
make[1]: *** [CMakeFiles/Makefile2:83: CMakeFiles/test.dir/all] Error 2
make[1]: Leaving directory '/mnt/d/dev/test/build'
make: *** [Makefile:91: all] Error 2

I am running the above on WSL Ubuntu 22.04.3 LTS (cmake Version 3.22.1).

Let me know if I missed any information.

Thanks!

Remove the quotes here. CMAKE_C_COMPILER is a list of command with arguments, not a space-separated string.

Same here. Just don’t make your life extra hard.

@hsattler , thanks for the suggestion:

I modified the following line:

set(CMAKE_C_COMPILER "${toolchain_dir}/${target_triple}-gcc ${compiler_flags}")

and removed the quotes:

set(CMAKE_C_COMPILER ${toolchain_dir}/${target_triple}-gcc ${compiler_flags})

And the generated build command now becomes:

"/opt/arm-gnu-toolchain/bin/arm-none-eabi-gcc;-mcpu=cortex-m7 -mthumb -specs=nano.specs -specs=nosys.specs" --sysroot=/opt/arm-gnu-toolchain/arm-none-eabi/lib/   "-mcpu=cortex-m7 -mthumb -specs=nano.specs -specs=nosys.specs" "-Wall -Wextra -Werror" -Wfatal-errors -MD -MT CMakeFiles/test.dir/main.c.o -MF CMakeFiles/test.dir/main.c.o.d -o CMakeFiles/test.dir/main.c.o -c /mnt/d/dev/test/main.c
/bin/sh: 1: /opt/arm-gnu-toolchain/bin/arm-none-eabi-gcc;-mcpu=cortex-m7 -mthumb -specs=nano.specs -specs=nosys.specs: not found

When I remove quotations from all the following 3 lines:

set(cpu_flags -mcpu=cortex-m7 -mthumb)
set(compiler_flags ${cpu_flags} -specs=nano.specs -specs=nosys.specs)
set(CMAKE_C_COMPILER ${toolchain_dir}/${target_triple}-gcc ${compiler_flags})

I get the following build command:

"/opt/arm-gnu-toolchain/bin/arm-none-eabi-gcc;-mcpu=cortex-m7;-mthumb;-specs=nano.specs;-specs=nosys.specs" --sysroot=/opt/arm-gnu-toolchain/arm-none-eabi/lib/   -mcpu=cortex-m7 -mthumb -specs=nano.specs -specs=nosys.specs "-Wall -Wextra -Werror" -Wfatal-errors -MD -MT CMakeFiles/test.dir/main.c.o -MF CMakeFiles/test.dir/main.c.o.d -o CMakeFiles/test.dir/main.c.o -c /mnt/d/dev/test/main.c
/bin/sh: 1: /opt/arm-gnu-toolchain/bin/arm-none-eabi-gcc;-mcpu=cortex-m7;-mthumb;-specs=nano.specs;-specs=nosys.specs: not found

Let me know if you have any more ideas.
Thanks!

Many of the variables in your CROSS Compiling options section need to be set before the first call to project(). They shouldn’t be specified by the project, they should be in a toolchain file. Putting them as you have here will result in CMake making all its initial toolchain decisions based on the default system compiler, not the one you’re trying to use. You will continue hitting problems if you don’t move most of them out to a toolchain file.

HI @craig.scott , Thanks for the inputs.

I moved the “Cross Compiling options” variables to another file “gcc-arm-none-eabi.cmake” in the same directory and modified the CMakeLists.txt as follows:

cmake_minimum_required(VERSION 3.22.0)
include(gcc-arm-none-eabi.cmake)
project(test VERSION 2.1.1)

######### Project Specific options
set(project_macros "-DMACRO1 -DMACRO2")
set(common_warnings "-Wall -Wextra -Werror")
set(extra_warnings "-Wfatal-errors")

add_executable(test main.c)
target_compile_options(test PRIVATE ${compiler_flags} ${common_warnings} ${extra_warnings})

I get the following output:

-- The C compiler identification is unknown
-- The CXX compiler identification is GNU 11.4.0
CMake Error at CMakeLists.txt:3 (project):
  The CMAKE_C_COMPILER:

    /opt/arm-gnu-toolchain/bin/arm-none-eabi-gcc -mcpu=cortex-m7 -mthumb -specs=nano.specs -specs=nosys.specs

  is not a full path to an existing compiler tool.

  Tell CMake where to find the compiler by setting either the environment
  variable "CC" or the CMake cache entry CMAKE_C_COMPILER to the full path to
  the compiler, or to the compiler name if it is in the PATH.


-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Check for working CXX compiler: /usr/bin/c++ - skipped
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring incomplete, errors occurred!
See also "/mnt/d/dev/test/build/CMakeFiles/CMakeOutput.log".
See also "/mnt/d/dev/test/build/CMakeFiles/CMakeError.log".

The PATH variable in my home bashrc contains the PATH to the toolchain. I also modified the PATH is /etc/profile to add toolchain path but that is also does not help.

Did I miss something while making the toolchain file?
Is there something else that I should have done ?

A yes, the CMAKE_C_COMPILER is just the compiler, the option go to another variable CMAKE_C_FLAGS_INIT.

In addition to the various corrections @hsattler has mentioned in his posts, you should also use the separate file as a toolchain file in the proper way. Rather than using include() before the project() command, pass that file with the --toolchain option on the cmake command line (there are a couple of other ways, but that’s the easiest). I recommend you have a read of the cmake-toolchains(7) manual, especially the Cross Compiling section.