How to Specify the Compiler and To Compile Differe

2019-08-05 11:08发布

问题:

My project is quite simple but I like to keep files in different folders for clarity. For instance I have three folders.

  • An Output folder that contains all the classes used for the output. (for now only Output.cc and Output.h).
  • A Math folder, containing all of the classes related to math. (vector.cc, vector.h, randomgen.h, randomgen.cc, etc)
  • A Tests folder where there are different cpp files each containing a main function. (Output_test.cc, vector_test.cc, etc)

How can I create a CMake script that complies all of the different main function of the different test programs using the classes that are in different folders? In addition, I didn't see where the compiler, and its options, are specified in a CMake file.

回答1:

How to specify the compiler?

There are a few ways to specify the compiler you want to use. Settings environment variables, defining compiler variables, or designating a generator.

Settings Environment Variables

There are two ways to use environment variables to help CMake determine which compiler to use during a CMake configuration. Using the PATH variable or the CC and CXX variables.

PATH

Make sure the path to your desired compiler is first in the list. If you don't want to modify your path, then use the 2nd option.

CC & CXX

CMake reads the variables CC and CXX to determine the path for the C compiler and C++ compiler respectively. Note that the first time CMake is configured for a project it will cache these paths, and look to the cache first for all future configurations. So if you wish to change the compiler path, be sure to delete the cache file CMakeCache.txt. As HughB pointed out, there is a good example of this given by Guillaume

Defining Compiler Variables

Similar to using CC and CXX, there are CMake variables that can be defined at the commandline to choose the desired compiler. They are CMAKE_C_COMPILER and CMAKE_CXX_COMPILER. You can set them using the -D option and they use the same values as CC and CXX. Note, just like CC and CXX these are cached after the first CMake configuration.

Example

cmake -DCMAKE_CXX_COMPILER=/usr/bin/g++4.6/g++ -DCMAKE_C_COMPILER=/usr/bin/gcc4.6/gcc <path to src>

Designating a Generator

The last way to choose the compiler is by using the -G option to select a generator. There are numerous generators to choose and I recently answered a question about them. I'm not going to go into too much detail about them in this answer, but you can read my other answer for more details.

Example

cmake -G "Unix Makefile" <path to src>

Don't Hardcode the Compiler

I recommend resisting the urge to "hardcode" the compiler in the CMakeLists.txt files. CMake is meant to be compiler independent and you should be setting the compiler information external of the CMake files. Use one of the methods mentioned above to keep your CMake files portable and to avoid confusion if yourself or someone else wants to build the project with a different compiler.

Related references. (Disclaimer: Written by me)

  • What is a CMake generator
  • Understanding the Purpose Behind CMake

How to Compile Multiple Executables?

As HughB mentioned use add_executables. You could also create separate libraries for each folder group, there are many ways to organize your project. I'm going to keep it simple and give an example that builds two executables in the same project.

For this example I created 5 files:

include/Helloworld.h

#include <stdio.h>

src/HelloWorld.cpp

#include "HelloWorld.h"

int main()
{
    printf("Hello World!\n");

    return 0;
}

include/HelloWorld2.h

#include <stdio.h>

src/HelloWorld2.cpp

#include "HelloWorld2.h"

int main()
{
    printf("Hello World2!\n");

    return 0;
}

CMakeLists.txt

cmake_minimum_required(VERSION 3.0)

# This is required to compile and must contain the paths to
# all of the header files
include_directories(include)

# These are optional, but are added to be passed to the
# add_executable command so that the headers are accessible 
# from within the project
set(HW_INCLUDES include/HelloWorld.h)
set(HW_INCLUDES2 include/HelloWorld2.h)

project(HelloWorlds)

# Required sources
set(HW_SOURCES src/HelloWorld.cpp)
set(HW_SOURCES2 src/HelloWorld2.cpp)

add_executable(HelloWorld ${HW_SOURCES} ${HW_INCLUDES}) 
add_executable(HelloWorld2 ${HW_SOURCES2} ${HW_INCLUDES2})

When this project is built there will be two executables: HelloWorld.exe and HelloWorld2.exe.



回答2:

Consider putting the code that will be used in different program mains in a library. Use the add_library command to do make a library. You could have a directory hierarchy like this:

TopDir
   CMakeLists.txt
   MyLib
      CMakeLists.txt
      vector.cc
      vector.h
      ....
   MyExe1
      CMakeLists.txt
      main1.cc
   MyExe2
      CMakeLists.txt
      main2.cc

Use add_subdirectory in your top level cmakelists.txt to traverse the directories. In the dirs that build executables, use add_executable and target_link_libraries. If you named the library MyLib then your target_link_libraries command would look like

target_link_libraries( exe1 MyLib )

In regard to overriding the compiler, see how to specify new gcc path for cmake