cmake use /clr

There are three options

(1) Collect the affected source files in dedicated directories with a
CMakeLists.txt and remove “-g” from CMAKE_{C,CXX}_FLAGS_DEBUG therein.
However, the sources must go into targets defined in the directory’s
CMakeLists.txt; maybe, you need to add particular static libraries
built from these sources, provided your toolchain supports this.

(2) Externalize the affected sources and reintegrate them as an
external project built with the same toolchain but different flags,
i.e. without “-g”; a radical approach with the same drawbacks as (1).

(3) If you get along with Makefile generators, you might use one of
the RULE_LAUNCH_COMPILE properties combined with a shell script:

cmake创建使用到/clr的项目

要删除debug版的/RTC1,有3种方案

    1. 给单个文件增加/clr并且删除CMAKE_CXX_FLAGS_DEBUG/RTC1标志
1
2
3
4
5
6
7
8
# test.cpp增加/clr /EHa属性
set_property(SOURCE test.cpp APPEND PROPERTY COMPILE_FLAGS "/clr /EHa")

# 删除/RTC1标记
if(CMAKE_CXX_FLAGS_DEBUG MATCHES "/RTC1")
string(REPLACE "/RTC1" " " CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG}")
message("CMAKE_CXX_FLAGS_DEBUG:${CMAKE_CXX_FLAGS_DEBUG}")
endif()
  • 2.把用到/clr的源文件构建成dll。在dll中删除CMAKE_CXX_FLAGS_DEBUG/RTC1标志

  • 3.使用RULE_LAUNCH_COMPILE与shell脚本结合:

CMakeLists.txt

1
2
3
4
5
6
7
8
9
10
11
CMAKE_MINIMUM_REQUIRED(VERSION 2.8 FATAL_ERROR)
PROJECT(EXAMPLE C)
SET(CMAKE_VERBOSE_MAKEFILE ON)
FILE(WRITE ${CMAKE_BINARY_DIR}/f.c "void f(void){}\n")
FILE(WRITE ${CMAKE_BINARY_DIR}/g.c "void g(void){}\n")
FILE(WRITE ${CMAKE_BINARY_DIR}/h.c "void h(void){}\n")
FILE(WRITE ${CMAKE_BINARY_DIR}/main.c "int main(void){return 0;}\n")
ADD_EXECUTABLE(main main.c f.c g.c h.c)
SET_TARGET_PROPERTIES(main PROPERTIES RULE_LAUNCH_COMPILE
"bash ${CMAKE_SOURCE_DIR}/setup <SOURCE> ${CMAKE_BINARY_DIR}/f.c
${CMAKE_BINARY_DIR}/h.c --")

setup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
SOURCE="$1"; shift
echo "SOURCE: $SOURCE"
unset FILES
while [ "$1" != "--" ]; do
FILES[${#FILES[@]}]="$1"; shift
done
shift
echo "FILES[${#FILES[@]}]: ${FILES[@]}"
CMDLINE0=("$1"); CMDLINE1=("$1"); shift
for i in "$@"; do
CMDLINE0[${#CMDLINE0[@]}]="$1"
if [ "$1" != "-g" ]; then CMDLINE1[${#CMDLINE1[@]}]="$1"; fi
shift
done
echo "CMDLINE0: ${CMDLINE0[@]}"
echo "CMDLINE1: ${CMDLINE1[@]}"
for i in "${FILES[@]}"; do
if [ "$i" == "$SOURCE" ]; then
echo "Executing ${CMDLINE1[@]}"; exec "${CMDLINE1[@]}"
fi
done
echo "Executing ${CMDLINE0[@]}"; exec "${CMDLINE0[@]}"

只使用Makefile构建项目时第3种方法较好。使用vs时第2种方法较好。

The setup script takes the source to compile, a list of source files to
be compiled without “-g” and the actual command line separated by “—“.
It stores the source and the files and constructs two command lines,
one without “-g”. Finally, it compares the source with each of the
files, and if there’s a match, it executes the shortened command
line without “-g”, otherwise the unaltered one.

IMO, (3) is a quite smart approach and should be favored if the project
doesn’t need to be built with generators other than the Makefile ones.

/RTC(运行时错误检查)

/RTC(运行时错误检查)

语法

/RTC1
/RTCc
/RTCs
/RTCu

参数

/RTC1
等效于 /RTCsu

/RTCc
报告何时向较小的数据类型赋值会导致数据丢失。 例如,它报告 short 类型值 0x0101 是否已分配给类型为 char 的变量。

此选项可以报告你要在什么情况下进行截断。 例如,当需要返回 int 的前 8 位作为 char 时。 由于 /RTCc 在分配导致信息丢失的情况下会导致运行时错误,因此请首先屏蔽所需的信息以避免运行时错误。 例如:

1
2
3
4
5
6
7
8
9
10
11
12
#include <crtdbg.h>

char get8bits(unsigned value, int position) {
_ASSERT(position < 32);
return (char)(value >> position);
// Try the following line instead:
// return (char)((value >> position) & 0xff);
}

int main() {
get8bits(12341235,3);
}

由于 /RTCc 拒绝符合标准的代码,因此 C++ 标准库不支持它。 使用 /RTCc 和 C++ 标准库的代码可能会导致编译器错误 C1189。 可以定义 _ALLOW_RTCc_IN_STL 来抑制警告并使用 /RTCc 选项。

/RTCs
启用堆栈帧运行时错误检查,如下所示:

  • 将局部变量初始化为非零值。 此选项有助于识别在调试模式下运行时未出现的 bug。 与发布版本相比,堆栈变量在调试版本中仍有零值的可能性更大。 这是因为在发布版本中对堆栈变量进行了编译器优化。 程序使用其堆栈的一个区域后,编译器永远不会将其重置为 0。 这意味着任何在以后恰好使用同一堆栈区域的未初始化堆栈变量都可以返回之前使用此堆栈内存留下的值。

  • 检测局部变量(如数组)的溢出和不足。 /RTCs 在访问因在结构中进行编译器填充而产生的内存时,不会检测到溢出。 如果使用 align、/Zp(结构成员对齐)或 pack,或者按某种方式对结构元素排序,因此需要编译器来添加填充,则可能会发生填充。

  • 堆栈指针验证,用于检测堆栈指针损坏。 堆栈指针损坏可能是由调用约定不匹配引起的。 例如,使用函数指针时,你调用 DLL 中的函数,该函数导出为 stdcall,但你将函数指针声明为 cdecl。

/RTCu
使用未初始化的变量时报告。 例如,生成警告 C4701 的指令也可能在 /RTCu 下生成运行时错误。 生成编译器警告(级别 1 和级别 4)C4700 的任何指令会在 /RTCu 下生成运行时错误。

但是,请考虑使用以下代码段:

1
2
3
4
int a, *b, c;
if ( 1 )
b = &a;
c = a; // No run-time error with /RTCu

如果变量可能已初始化,则不会由 /RTCu 在运行时报告该变量。 例如,通过指针为变量设置别名后,编译器不会跟踪变量并报告未初始化的用途。 实际上,可以通过获取变量的地址来初始化变量。 在这种情况下,& 运算符的作用类似于赋值运算符。

注解

运行时错误检查是一种在运行代码的过程中发现问题的方法;有关详细信息,请参阅如何:使用原生运行时检查。

可以在命令行中指定多个 /RTC 选项。 可以组合使用选项参数,例如,/RTCcu 等同于 /RTCc /RTCu

如果使用任何 /RTC 编译器选项在命令行中编译程序,则代码中的任何 pragma optimize 指令都会以无提示方式失败。 这是因为运行时错误检查在发布(已优化)版本中无效。

请将 /RTC 用于开发版本;请勿将 /RTC 用于发布版本。 /RTC 不能与编译器优化(/O 选项(优化代码))配合使用。 使用 /RTC 生成的程序映像比使用 /Od 生成的映像稍微大一些,也稍微慢一些(最多比 /Od 版本慢 5%)。

使用任何 /RTC 选项或 /GZ 时,将定义 __MSVC_RUNTIME_CHECKS 预处理器指令。

在 Visual Studio 开发环境中设置此编译器选项

  • 1.打开项目的“属性页” 对话框。 有关详细信息,请参阅在 Visual Studio 中设置 C++ 编译器和生成属性。

  • 2.选择“配置属性”>“C/C++”>“代码生成”属性页面 。

  • 3.修改以下属性中的一个或两个属性:基本运行时检查或较小的类型检查