C\C++ 11

C\C++11 特性

Posted by nomadli on January 4, 2016

C++ 内存布局

  • 4 扩展
  • clang++ -cc1 -emit-llvm -fdump-record-layouts -fdump-vtable-layouts -std=c++17 1.cpp
  • g++ -fdump-class-hierarchy -std=c++17 -c 1.cpp c++filt -n
  • g++ 内存布局文档 Itanium C++ ABI
  • vc++将虚基类的偏移量单独用一个额外的指针进行索引;将空子类的虚指针,或者或者具有与基类相同虚函数接口的派生类的虚指针与虚基类的虚指针进行合并.
  • 编译期在不同对象成员函数调用时,假设this指针是当前标识类型,因此运行时需要动态修改this
  • 构造函数: 内存0->主父类构造虚函数表指针(vfptr)为主父类的即完全就是主父类的对象->偏移->父类2构造函数vfptr为父类2的即完全就是主类2的对象->…->子类构造修改vfptr.凌形继承比较复杂
  • 析构函数: 子类析构利用子类vfptr调用的是子类的函数->修改vfptr为父类vfptr->偏移->父类n析构函数->…->主父类
  • 单继承内存模型: vfptr在对象的起始地址,每个虚函数的偏移量在基类型和派生类型中均相同,这使得虚函数相对于vfptr的偏移在编译时确定.由于vfptr位置满足编译期假设,this无需修改.
    class A {
      int ax;
      virtual void AFun1() {}
      virtual void AFun2() {}             //  |   offset_to_top(0)  |
      void AFun3();                       //  |        A RTTI       |
    } a;//A.vfptr---------------------------//  |  void A::AFun1()    |
      //int ax                            //  |  void A::AFun2()    |
    class B : public A {
      int bx;
      virtual void BFun1() {};
      virtual void BFun2() {};            //  |   offset_to_top(0)  |
      void AFun1() override {};           //  |        B RTTI       |
    } b;//A.vfptr|B.vfptr-------------------//  |  void B::AFun1()    |
      //int ax                            //  |  void A::AFun2()    |
      //int bx                            //  |  void B::BFun1()    |
                                          //  |  void B::BFun2()    |
    
  • 多继承基类独立内存模型: 为了满足编译期this指针假设,需要将基类vfptr独立无法合并,此时当B指针实际指向C对象,地址是C对象的vfptr内存地址,此时调用C复写的函数时,指针需要+offset_to_top,即此时vfptr中函数并没有真正指向C的复写函数而是指向Thunks表,表内的函数将this+offset_to_top然后调用C对象第一个vfptr中的函数
    class A {
      int ax;
      virtual void AFun1() {}
      virtual void AFun2() {}
    };
    class B {
      int bx;
      virtual void BFun1() {};
      virtual void BFun2() {};
    };
    class C : public A, public B
    {
      int cx;
      virtual void CFun1() {};
      virtual void CFun2() {};
      void AFun1() override {};           //  |   offset_to_top(0)  |
      void BFun2() override {};           //  |        C RTTI       |
    } c;//A.vfptr|C.vfptr-------------------//  |  void C::AFun1()    |
      //int ax                            //  |  void A::AFun2()    |
      //B.vfptr----------------------|    //  |  void C::CFun1()    |
      //int bx                       |    //  |  void C::CFun2()    |
      //int cx                       |    //  |  void C::BFun2()    |
      //这里为B基类this指针偏移即       |    //  | offset_to_top(-16)  |
      //这里多一个为了完全模拟B的vfptr   |    //  |        C RTTI       |
      //                             +----//  |  void B::BFun1()    |
                                          //  |Thunk void C::BFun2()|
    
  • 虚继承的内存模型: virtual继承vbase_offset用来表示virtual父类偏移,解决凌形继承
    class A {
      int ax;
      virtual void AFun1() {}
      virtual void AFun2() {}
    }
    class B : virtual public A {
      int bx;
      virtual void BFun1() {};//运行时确定  //  |   vbase_offset(16)  |
      virtual void BFun2() {};            //  |   offset_to_top(0)  |
      void AFun1() override {};           //  |        B RTTI       |
    } b;//B.vfptr---------------------------//  |  void B::BFun1()    |
      //int bx                            //  |  void B::BFun2()    |
      //A.vfptr---------------------|     //  |  void B::AFun1()    |
      //int ax虚基最后一个虚函数this偏移|     //  |  vcall_offset(0)    |
      //虚基类倒数第二个虚函数this偏移量 |     //  |  vcall_offset(-16)  |
      //                            |     //  | offset_to_top(-16)  |
      //                            |     //  |        B RTTI       |
      //T表函数将this+对应vcall_offset+-----//  |Thunk void B::AFun1()|
                                          //  |  void A::AFun2()    |
    
  • 菱形继承的内存模型
    class A {
      int ax;
      virtual void AFun1() {}
      virtual void AFun2() {}
    }
    class B : virtual public A {
      int bx;
      virtual void BFun1() {};
      virtual void BFun2() {};
      void AFun1() override {};
    }
    class C : virtual public A {
      int cx;
      virtual void CFun1() {};
      virtual void CFun2() {};
      void AFun1() override {};
    }
    class D : virtual public A {
      int dx;
      virtual void DFun1() {};
      virtual void DFun2() {};
    }
    class E : public B, public C {
      int ex;
      virtual void EFun1() {};//运行时确定  //  |   vbase_offset(32)  |
      virtual void EFun2() {};            //  |   offset_to_top(0)  |
      void AFun1() override {};           //  |        E RTTI       |
    } e;//B.vfptr|E.vfptr-------------------//  |  void B::BFun1()    |
      //int bx                            //  |  void B::BFun2()    |
      //C.vfptr---------------------|     //  |  void E::AFun1()    |
      //int cx                      |     //  |  void E::EFun1()    |
      //int ex                      |     //  |  void E::EFun2()    |
      //A.vfptr-------------|       |     //  |   vbase_offset(16)  |
      //int ax              |       |     //  | offset_to_top(-16)  |
      //                    |       |     //  |        E RTTI       |
      //                    |       +-----//  |  void C::CFun1()    |
      //                    |             //  |  void C::CFun2()    |
      //                    |             //  |Thunk void E::AFun1()|
      //                    |             //  |  vcall_offset(0)    |
      //                    |             //  |  vcall_offset(-32)  |
      //                    |             //  |  offset_to_top(-32) |
      //                    |             //  |        E RTTI       |
      //                    +-------------//  |Thunk void E::AFun1()|
      //                                  //  |  void A::AFun2()    |
    class F : public B, public D {
      int fx;                 //运行时确定  //  |   vbase_offset(32)  |
      virtual void FFun1() {};            //  |   offset_to_top(0)  |
      virtual void FFun2() {};            //  |        F RTTI       |
    } f;//B.vfptr|F.vfptr-------------------//  |  void B::BFun1()    |
      //int bx                            //  |  void B::BFun2()    |
      //D.vfptr---------------------|     //  |  void B::AFun1()    |
      //int dx                      |     //  |  void F::FFun1()    |
      //int fx                      |     //  |  void F::FFun2()    |
      //A.vfptr-------------|       |     //  |   vbase_offset(16)  |
      //int ax              |       |     //  | offset_to_top(-16)  |
      //                    |       |     //  |        F RTTI       |
      //                    |       +-----//  |  void D::DFun1()    |
      //                    |             //  |  void D::DFun2()    |
      //                    |             //  |Thunk void E::AFun1()|
      //                    |             //  |  vcall_offset(0)    |
      //                    |             //  |  vcall_offset(-32)  |
      //                    |             //  |  offset_to_top(-32) |
      //                    |             //  |        F RTTI       |
      //                    +-------------//  |Thunk void B::AFun1()|
      //                                  //  |  void A::AFun2()    |
    class G : public D, public B {
      int gx;                 //运行时确定  //  |   vbase_offset(32)  |
      virtual void FFun1() {};            //  |   offset_to_top(0)  |
      virtual void FFun2() {};            //  |        G RTTI       |
    } f;//D.vfptr|G.vfptr-------------------//  |  void D::DFun1()    |
      //int dx                            //  |  void D::DFun2()    |
      //B.vfptr---------------------|     //  |  void G::GFun1()    |
      //int bx                      |     //  |  void G::GFun2()    |
      //int gx                      |     //  |   vbase_offset(16)  |
      //A.vfptr-------------|       |     //  | offset_to_top(-16)  |
      //int ax              |       |     //  |        G RTTI       |
      //                    |       +-----//  |  void B::BFun1()    |
      //                    |             //  |  void B::BFun2()    |
      //                    |             //  |  void B::AFun1()    |
      //                    |             //  |  vcall_offset(0)    |
      //                    |             //  |  vcall_offset(-16)  |
      //                    |             //  |  offset_to_top(-32) |
      //                    |             //  |        G RTTI       |
      //                    +-------------//  |Thunk void B::AFun1()|
      //                                  //  |  void A::AFun2()    |
    
  • 虚继承导致的析构时,公共基类的偏移都不相同,无法直接用公共基类的虚表,因此在对象构造时采用多虚表的方式.如上述E类,E类的B、C类虚表与B、C类自己的虚表是不同的,因此编译器添加两个虚表B-in-E及C-in-E,采用需指针的方式在析构时指定不同的虚表进入父类析构,这些新表叫Virtual Table Table(VTT)

工具

  • c++filt gc++filt _xxxx 符号还原

C++ 11

  1. auto 使用计算的实际类型,忽略顶层的const auto 函数名()->返回类型

  2. decltype 不计算只推断类型,变量与表达式结果不同 自动生成返回类型

  3. 语法特点 % 取被余数的符号,商向0靠 {} 初始化不允许丢失精度,可用于return 位运算 对符号位没定义,移位超出或负数未定义 sizeof运算符不求值、可以使用类作用域来访问属性 for(declaration:expression) 容器不可以在循环中增删,因为预存了end using name=type 等价 typedef 不同作用域不会重载函数,引用、指针有const修饰也是重载
  4. override 明确此函数是复写父类的virtual函数

C K&R - 89 - 95

C 98

  1. register 编译优化时尽量将变量保存在寄存器中
  2. volatile 变量会被其它线程修改,每次使用读取内存

C 99

  1. inline
  2. restrict 修饰指针 表示此指针生命周期内是这块内存地址的唯一指针

    int add(int *restrict a, int *restrict b) {
        *a = 5;
        *b = 6;
        return *a + *b;这里不用担心a与b指向相同的内存,因此汇编时不需要判断a指向的值变成6.
    }
    
  3. _Bool 是数字不能用true false
  4. _Complex 复数
  5. _Imaginary 虚数
  6. 动态数组 char data[len]; 可以用变量定义数组长度

C 11 - 17

  1. alignof aligned_alloc
  2. _Noreturn void fxxx(xxx) 无法返回
  3. _Generic 泛型函数

    void* func_int(int x){....}
    void* func_float(float x){....}
    void* func_char(char x){....}
    void* func_str(char *x){....}
    #define func_all(x) _Generic((x), int:func_int, float:func_float, char:func_char, char*:func_str, default:func_int)(x);
    也可以是变量
    int a, c = 0;
    _Generic(x, int:a, float:c, default:a)++
    
  4. 语言线程支持 thread_local thrd_create thrd_exit mtx_lock mtx_unlock
  5. _Atomic
  6. Unicode 支持
  7. quick_exit() exit()失败后,可以强制结束
  8. CMPLX() 复数宏
  9. struct timespec 纳秒支持
  10. _Alignas 在定义前 指定字节对齐

        _Alignas(4) int x;
        _Alignas(8) struct name {....}
    
  11. _Alignof 获取变量 类型的对齐方式
  12. _Atomic 原子变量 atomic_store 等
  13. _Static_assert 编译起的assert

命令行参数

#include <argp.h>
static const struct argp_option opts[] = {
	{ "verbose", 'v', NULL, 0, "Verbose debug output" },
	{ "duration", 'd', "DURATION-MS", 0, "Minimum process duration (ms) to report" },
	{},
};
static error_t parse_arg(int key, char *arg, struct argp_state *state) {
	switch (key) {
	case 'v':
		break;
	case 'd':
		break;
	case ARGP_KEY_ARG:
		argp_usage(state);
		break;
	default:
		return ARGP_ERR_UNKNOWN;
	}
	return 0;
}
static const struct argp myargp = {
	.options = opts,
	.parser = parse_arg,
	.doc = "xxxxxxxxxx",
};
err = argp_parse(&myargp, argc, argv, 0, NULL, NULL);

C

  • link参数 -Bsymbolic-functions 确保使用动态库自己定义的全局变量和函数, 深度优先

daemon

  • fork 如果当前进程是进程组组长, 则setsid()会失败; 如果是从shell启动,则可以继续执行shell
  • setsid 切断与shell的关系,成为组长; 不再响应SIGIN、SIGQUIT、SIGTSP等, 远程断开也继续
  • umask(0) 使deamon创建的文件根shell无关
  • fork 防止程序后面调用open(“/dev/console”, O_RDWR); fork后不再是组长,所以无权打开console
  • chdir(“/”)
  • close(stdin);
  • close(stdout);
  • close(stderr);
  • stdin = open(“/dev/null”);
  • dup2(stdin, STDOUT_FILENO);
  • dup2(stdin, STDERR_FILENO);
  • system()串行、popen()并行 -> fork+exec+waitpid
  • posix_spawn=fork+exec, system

嵌入汇编

  1. asm volatile(“.intel_syntax /n/t” “汇编/n/t” “.att_syntax /n/t”); intel at&t切换
  2. llvm-as 将可读的 .ll 文件汇编成字节代码
  3. llvm-dis 将字节代码文件反编成可读的 .ll 文件
  4. opt 在一个字节代码文件上运行一系列的 LLVM 到 LLVM 的优化
  5. llc 为一个字节代码文件生成本机器代码
  6. lli 直接运行使用 JIT 编译器或者解释器编译成字节代码的程序
  7. llvm-link 将几个字节代码文件连接成一个
  8. llvm-ar 打包字节代码文件
  9. llvm-ranlib 为 llvm-ar 打包的文件创建索引
  10. llvm-nm 在 字节代码文件中打印名字和符号类型
  11. llvm-prof 将 ‘llvmprof.out’ raw 数据格式化成人类可读的报告
  12. llvm-ld 带有可装载的运行时优化支持的通用目标连接器
  13. llvm-config 打印出配置时 LLVM 编译选项、库、等等
  14. llvmc 一个通用的可定制的编译器驱动
  15. llvm-diff 比较两个模块的结构
  16. bugpoint 自动案例测试减速器
  17. llvm-extract 从 LLVM 字节代码文件中解压出一个函数
  18. llvm-bcanalyzer 字节代码分析器 (分析二进制编码本身,而不是它代表的程序)
  19. FileCheck 灵活的文件验证器,广泛的被测试工具利用
  20. tblgen 目标描述阅读器和生成器
  21. lit LLVM 集成测试器,用于运行测试

编译指令

  1. NS_FORMAT_FUNCTION(F,A) = __attribute__((format(__NSString__,F,A)) 第F个参数是格式化字符串类型是NSString,从A开始检查匹配,放函数声明末尾。
  2. __attribute__((format(printf,F,A))同上C语言。
  3. void __attribute__((noreturn)) FUNC 函数永远不返回。
  4. NS_DEPRECATED_IOS=__attribute__((availability(macosx/ios,introduced=4.0,deprecated=7.0,obsoleted=9.0,message=””))) 函数末尾 指定函数开始版本、废弃版本、彻底不能使用版本、警告信息。
  5. __attribute__((warn_unused_result)) 函数末尾 检查函数调用是否使用返回值,没有使用警告。
  6. __attribute__((constructor(num))) 函数最前面 在main函数之前调用的函数,num[101,)表示优先级,数字小优先级高,100以下系统占用。
  7. __attribute__((destructor)) 函数最前面 在进程退出时调用。
  8. __attribute__((cleanup(函数指针))) 变量名后 在出变量的作用域后执行函数。技巧定义一个未使用的block变量在block里它的释放函数里做释放其他变量:__strong void(^block)(void) __attribute__((cleanup(blockCleanUp),unused)) = ^{};定义一个block变量在出block作用域后调用blockCleanUp,blockCleanUp调用block.
  9. __attribute__((objc_subclassing_restricted)) 在interface前 禁止被继承。
  10. __attribute__((objc_requires_super))接口声明后,子类复写这个方法时必须调用父方法。
  11. __attribute__((objc_boxable)) struct名后 使struct可以使用{}初始化。
  12. __attribute__((enable_if(条件,提示))) 函数后 判断参数等条件,只能C函数使用。
  13. __attribute__((overloadable)) 函数前面 C编译器重置函数。
  14. __attribute__((objc_runtime_name(name))) @interface 或 @protocol前面,指定运行时class名称。
  15. __attribute__((constructor)) //在main函数之前调用
  16. __attribute__((destructor)) //在main函数之后调用
  17. __attribute__((aligned(8))) //字节对其
  18. __attribute__((__packed__)) //紧密排列
  19. __attribute__((__transparent_union__)) //可以实现动态类型参数,即将传入参数转为联合体
  20. __attribute__((visibility(“default”))) //符号的可见性 default internal hidden protected
  21. #pragma unroll(4) 告诉编译器下面的循环可以展开四层即for(){a[i]=x;}变为for(){a[i]=x;a[i+1]=x;…}-O1,-O2,-O3则无效
  22. #pragma MUST_INTERAT(1)不要进行循环展开
  23. #pragma mark - 代码分类
  24. #pragma clang diagnostic push clang参数压栈
  25. #pragma clang diagnostic pop clang参数出栈
  26. #pragma clang diagnostic warning “-W*” 添加警告
  27. #pragma clang diagnostic ignored “-W*” 取消某警告 文章末尾列表
  28. #pragma clang assume_nonnull begin
  29. #pragma clang assume_nonnull end
  30. #pragma GCC visibility push(default) #pragma GCC visibility pop
  31. __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ __ORDER_BIG_ENDIAN__
  32. __attribute__((__nonnull__(1,3,….))) 指定第几个参数不能为空
  33. __attribute__((__nonnull__)) 指定所有参数不能为空
  34. __attribute__((__sentinel__)) 指定不定参数需要以NULL为结尾
  35. __attribute__((__symver__(“foo@VERS_2”), …)) 定义函数版本 asm (“.symver memcpy, memcpy@GLIBC_2.2.5”);
  36. __attribute__((alias (“foo_v1”))) 重命名 ``` #ifdef clang #pragma clang diagnostic push clang #pragma clang diagnostic ignored “-Wxxx” #elif defined(GNUC) #pragma GCC diagnostic push #pragma GCC diagnostic ignored “-Wxxx” #elif defined(_MSC_VER) #pragma warning(push) #pragma warning(disable:xxxx) #endif

#ifdef clang #pragma clang diagnostic pop clang #elif defined(GNUC) #pragma GCC diagnostic pop #elif defined(_MSC_VER) #pragma warning(pop) #endif

#if defined(linux) || defined(__linux) || defined(linux)

define SYS_NAME “Linux”

#elif defined(MSYS)

define SYS_NAME “MSYS”

#elif defined(CYGWIN)

define SYS_NAME “Cygwin”

#elif defined(MINGW32)

define SYS_NAME “MinGW”

#elif defined(APPLE)

define SYS_NAME “Darwin”

#elif defined(_WIN32) || defined(WIN32) || defined(WIN32)

define SYS_NAME “Windows”

#elif defined(FreeBSD) || defined(__FreeBSD)

define SYS_NAME “FreeBSD”

#elif defined(NetBSD) || defined(__NetBSD)

define SYS_NAME “NetBSD”

#elif defined(OpenBSD) || defined(__OPENBSD)

define SYS_NAME “OpenBSD”

#elif defined(__sun) || defined(sun)

define SYS_NAME “SunOS”

#elif defined(_AIX) || defined(AIX) || defined(__AIX) || defined(aix) || defined(__aix)

define SYS_NAME “AIX”

#elif defined(hpux) || defined(__hpux)

define SYS_NAME “HP-UX”

#elif defined(HAIKU)

define SYS_NAME “Haiku”

#elif defined(BeOS) || defined(__BEOS) || defined(_BEOS)

define SYS_NAME “BeOS”

#elif defined(QNX) || defined(QNXNTO)

define SYS_NAME “QNX”

#elif defined(tru64) || defined(_tru64) || defined(__TRU64)

define SYS_NAME “Tru64”

#elif defined(riscos) || defined(__riscos)

define SYS_NAME “RISCos”

#elif defined(sinix) || defined(__sinix) || defined(SINIX)

define SYS_NAME “SINIX”

#elif defined(UNIX_SV)

define SYS_NAME “UNIX_SV”

#elif defined(bsdos)

define SYS_NAME “BSDOS”

#elif defined(_MPRAS) || defined(MPRAS)

define SYS_NAME “MP-RAS”

#elif defined(osf) || defined(__osf)

define SYS_NAME “OSF1”

#elif defined(_SCO_SV) || defined(SCO_SV) || defined(sco_sv)

define SYS_NAME “SCO_SV”

#elif defined(ultrix) || defined(__ultrix) || defined(_ULTRIX)

define SYS_NAME “ULTRIX”

#elif defined(XENIX) || defined(_XENIX) || defined(XENIX)

define SYS_NAME “Xenix”

#elif defined(WATCOMC)

if defined(LINUX)

define SYS_NAME “Linux”

elif defined(DOS)

define SYS_NAME “DOS”

elif defined(OS2)

define SYS_NAME “OS2”

elif defined(WINDOWS)

define SYS_NAME “Windows3x”

elif defined(VXWORKS)

define SYS_NAME “VxWorks”

else

define SYS_NAME “Unknown”

endif

#elif defined(__INTEGRITY)

if defined(INT_178B)

define SYS_NAME “Integrity178”

else /* regular Integrity */

define SYS_NAME “Integrity”

endif

#elif defined(_ADI_COMPILER)

define SYS_NAME “ADSP”

#else /* unknown platform */

define SYS_NAME “Unknown”

#endif

#if defined(_WIN32) && defined(_MSC_VER)

if defined(_M_IA64)

define ARCH_NAME “IA64”

elif defined(_M_ARM64EC)

define ARCH_NAME “ARM64EC”

elif defined(_M_X64) || defined(_M_AMD64)

define ARCH_NAME “x64”

elif defined(_M_IX86)

define ARCH_NAME “X86”

elif defined(_M_ARM64)

define ARCH_NAME “ARM64”

elif defined(_M_ARM)

if _M_ARM == 4

define ARCH_NAME “ARMV4I”

elif _M_ARM == 5

define ARCH_NAME “ARMV5I”

else

define ARCH_NAME “ARMV” # _M_ARM

endif

elif defined(_M_MIPS)

define ARCH_NAME “MIPS”

elif defined(_M_SH)

define ARCH_NAME “SHx”

else

define ARCH_NAME “Unknown”

endif

#elif defined(WATCOMC)

if defined(_M_I86)

define ARCH_NAME “I86”

elif defined(_M_IX86)

define ARCH_NAME “X86”

else

define ARCH_NAME “Unknown”

endif

#elif defined(IAR_SYSTEMS_ICC) || defined(__IAR_SYSTEMS_ICC)

if defined(ICCARM)

define ARCH_NAME “ARM”

elif defined(ICCRX)

define ARCH_NAME “RX”

elif defined(ICCRH850)

define ARCH_NAME “RH850”

elif defined(ICCRL78)

define ARCH_NAME “RL78”

elif defined(ICCRISCV)

define ARCH_NAME “RISCV”

elif defined(ICCAVR)

define ARCH_NAME “AVR”

elif defined(ICC430)

define ARCH_NAME “MSP430”

elif defined(ICCV850)

define ARCH_NAME “V850”

elif defined(ICC8051)

define ARCH_NAME “8051”

elif defined(ICCSTM8)

define ARCH_NAME “STM8”

else

define ARCH_NAME “Unknown”

endif

#elif defined(ghs)

if defined(PPC64)

define ARCH_NAME “PPC64”

elif defined(ppc)

define ARCH_NAME “PPC”

elif defined(ARM)

define ARCH_NAME “ARM”

elif defined(x86_64)

define ARCH_NAME “x64”

elif defined(i386)

define ARCH_NAME “X86”

else

define ARCH_NAME “Unknown”

endif

#elif defined(clang) && defined(ti)

if defined(__ARM_ARCH)

define ARCH_NAME “Arm”

else

define ARCH_NAME “Unknown”

endif

#elif defined(TI_COMPILER_VERSION)

if defined(TI_ARM)

define ARCH_NAME “ARM”

elif defined(MSP430)

define ARCH_NAME “MSP430”

elif defined(TMS320C28XX)

define ARCH_NAME “TMS320C28x”

elif defined(TMS320C6X) || defined(_TMS320C6X)

define ARCH_NAME “TMS320C6x”

else

define ARCH_NAME “Unknown”

endif

#elif defined(ADSPSHARC)

define ARCH_NAME “SHARC”

#elif defined(ADSPBLACKFIN)

define ARCH_NAME “Blackfin”

#elif defined(TASKING)

if defined(CTC) || defined(CPTC)

define ARCH_NAME “TriCore”

elif defined(CMCS)

define ARCH_NAME “MCS”

elif defined(CARM)

define ARCH_NAME “ARM”

elif defined(CARC)

define ARCH_NAME “ARC”

elif defined(C51)

define ARCH_NAME “8051”

elif defined(CPCP)

define ARCH_NAME “PCP”

else

define ARCH_NAME “Unknown”

endif

#else

define ARCH_NAME “Unknown”

#endif


# clang & gcc 编译指令
01. -c 只是编译不链接,生成目标文件“.o”
02. -S 只是编译不汇编,生成汇编代码
03. -E 只进行预编译,不做其他处理
04. -g 在可执行程序中包含标准调试信息
05. -o file 把输出文件输出到file里  
06. -I dir 在头文件的搜索路径列表中添加dir目录
07. -L dir 在库文件的搜索路径列表中添加dir目录
08. clang –target=aarch64-linux-gnu –O1 -emit-llvm -c xx.c -o xx.bc 生成bitcode
09. clang –target=aarch64-linux-gnu –O1 -emit-llvm -S xx.c -o xx.ll 生成LLVM IR文件
09. –target 指定目标,生成IR不同, O1减少优化为了可读
09. IR文件中 target datalayout="e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
09. -分隔;e小端E大段;m:e是mangling格式为ELF;ix:y:z表示xbit的数据对齐方式是ybit首选对齐是zbit
09. n寄存器大小32和64位;S栈对齐方式128位对齐
10. llvm-as test.ll 将llvm汇编转bitcode
11. llvm-dis test.bc 将bitcode转llvm汇编
12. llc test.bc -o test.s ||  llc test.ll -o test.s 转平台汇编
13. -ffreestanding -nostdlib 链接标识, 将libc直接链接进可执行文件, 某些嵌入式没有c运行时
14. -fprofile-arcs -ftest-coverage 代码覆盖率参数,检查代码是否无用
15. -ansi –pedantic 不使用编译器扩展语法
16. clang -cc1 -fdump-record-layouts -stdlib=libc++ xx.cpp 打印类对象内存布局
17. clang -Xclang -fdump-vtable-layouts -stdlib=libc++ -c xx.cpp 打印虚函数表内存布局 Xclang将参数传给CC1前端|-mllvm参数传给后端 
18. g++ -fdump-class-hierarchy xx.cpp 打印虚函数表内存布局
19. clang++ -Xclang -ast-print -fsyntax-only -std=c++17 xx.cpp 将模板展开  ast-print打印语法树 fsyntax-only只解析语法不编译链接

# 优化
01. ld 有一个Order File参数读取x.order文件,里面是实际的函数排序如-[LBOCTools lbCurrentPresentingVC],相关函数放入同一个内存页会提高性能。
02. Link Map可以写入文件,用来检测符号的地址
03. -fsanitize-coverage=[func|bb|edge]<,no-prune>,[trace-pc-guard|trace-pc] 覆盖率插桩
    01. func只回调函数调用
    02. bb块调用,如循环
    03. edge 边缘触发, 当某块条件不成立跳过时会调用并传入一个虚拟块
    04. no-prune 不要修剪, 可以更准确的判断代码
04. -finstrument-functions 函数调用插桩
05. fprofile 典型运行场景分析, 协助优化逻辑分支

# 工具
01. objdump
02. otool(mac)
03. codesign(mac)
04. lipo(mac)
05. nm
    参数
    -A 每行或者显示全路径名称或者显示对象库名。
    -B 在 Berkeley 软件分发(BSD)格式中显示输出:值   类型   名称
    -C 限制解码(demangle) C++ 名称。缺省是解码所有 C++ 符号名。
    C++ 对象文件中的符号在被使用前它们的名称已经被解码了。
    -d 用十进制显示符号的值和大小。这是缺省的。
    -e 只显示静态的和外部的(全局)符号。
    -f 显示完整的输出,包括冗余的 .text、 .data 以及 .bss 符号,这些在常都是被限制的。
    -g 只显示外部的(全局)符号。
    -h 限制输出头数据的显示。
    -l 通过给 WEAK 符号的编码键附加一个 * 来区分 WEAK 和 GLOBAL 符号。如果和 -P 选项一起使用, WEAK 符号的符号类型显示如下:
            V Weak Data 符号
            W Weak Text 符号
            w Weak 未定义符号
            Z Weak bss 符号
    -o 用八进制而不是十进制数来显示符号的值和大小。
    -P 以标准可移植输出格式显示信息: 库/对象名  名称   类型   值   大小
    该格式以十六进制符号表示法显示数字值,除非您用 -t、-d 或 -o 标志指定同的格式。 如果您指定了 -A 标志 -P 标志只显示 库/对象名字段。同样-P 标志只显示大小适用的符号大小字段。
    -p	不排序。输出按符号表顺序打印。
    -r	倒序排序。
    -T	把可能会溢出它的列的每个名字截短,使显示的名字的最后一个字符星号(*)。 缺省情况下,nm 显示列出的符号的全名,并且一个比为其设置的的宽度长的名称会引起名称后的每个列无法对齐。
    -t Format	显示指定格式下的数字值,其中 Format 参数是以下符号示法之一:
            d 十进制符号表示法。这是 nm 命令的缺省格式。
            o 八进制符号表示法。
            x 十六进制符号表示法。
    -u	只显示未定义符号。
    -v	按值而不是按字母表顺序排序输出。
    -x	用十六进制而不是十进制数来显示符号的值和大小。
    -X mode	指定 nm 应该检查的对象文件的类型。 mode 必须是下列之一:
            32 只处理 32 位对象文件
            64 只处理 64 位对象文件
            32_64 处理 32 位和 64 位对象文件
            缺省是处理 32 位对象文件(忽略 64 位对象)。 mode 也可以 OBJECT_MODE 环境变量来设置。例如,OBJECT_MODE=64 使 nm 处理任何 64 位对象并且忽略 32 位对象。 -X 标志覆盖 OBJECT_MODE 变量。
            
    符号标识 大小全局 小写局部
    - A 该符号的值是绝对的,在以后的链接过程中,不允许进行改变。这样的符值,常常出现在中断向量表中,例如用符号来表示各个中断向量函数在中断向量中的位置。
    - B 该符号的值出现在非初始化数据段(bss)中。例如,在一个文件中定义全static int test。则该符号test的类型为b,位于bss section中。其值表该符号在bss段中的偏移。一般而言,bss段分配于RAM中
    - C 该符号为common。common symbol是未初始话数据段。该符号没有包含一个普通section中。只有在链接过程中才进行分配。符号的值表示该符号需要字节数。例如在一个c文件中,定义int test,并且该符号在别的地方会被引用则该符号类型即为C。否则其类型为B。
    - D 该符号位于初始话数据段中。一般来说,分配到data section中。例如定全局int baud_table[5] = {9600, 19200, 38400, 57600, 115200}则会分配于初始化数据段中。
    G 该符号也位于初始化数据段中。主要用于small object提高访问smalldata object的一种方式。
    - I 该符号是对另一个符号的间接引用。
    - N 该符号是一个debugging符号。
    - R 该符号位于只读数据区。例如定义全局const int test[] = {123,123};则test就是一个只读数据区的符号。注意在cygwin下如果使用gcc直接译成MZ格式时,源文件中的test对应_test,并且其符号类型为D,即初始化数段中。但是如果使用m6812-elf-gcc这样的交叉编译工具,源文件中的test对目标文件的test,即没有添加下划线,并且其符号类型为R。一般而言,位rodata section。值得注意的是,如果在一个函数中定义const char *test= “abc”, const char test_int = 3。使用nm都不会得到符号信息,但是符串“abc”分配于只读存储器中,test在rodata section中,大小为4。
    - S 符号位于非初始化数据区,用于small object。
    - T 该符号位于代码区text section。
    - U 该符号在当前文件中是未定义的,即该符号的定义在别的文件中。例如,当文件调用另一个文件中定义的函数,在这个被调用的函数在当前就是未定义的;是在定义它的文件中类型是T。但是对于全局变量来说,在定义它的文件中,其符类型为C,在使用它的文件中,其类型为U。
    - V 该符号是一个weak object。
    - W The symbol is a weak symbol that has not beenspecifically tagged as a weak object symbol.
    - 该符号是a.out格式文件中的stabs symbol。
        - ? 该符号类型没有定义

06. objcopy --redefine-sym xx.a=yy.a
07. clang-format
08. scan-build、infer
09. gcov gprof 覆盖率及性能分析

# 头文件搜索
1. C_INCLUDE_PATH   xx:xx
2. CPLUS_INCLUDE_PATH xx:xx
3. OBJC_INCLUDE_PATH xx:xx
4. -nostdinc 不搜索系统路径及上诉变量指定的路径
5. PKG_CONFIG_PATH

# 库搜索优先级
1. RPATH  -Wl,-rpath,'$ORIGIN/xxx' SET_TARGET_PROPERTIES(target PROPERTIES INSTALL_RPATH "$ORIGIN;/xx/")
2. 环境变量LD_LIBRARY_PATH指定的动态库搜索路径
3. RUNPATH
4. 配置文件/etc/ld.so.conf中指定的动态库搜索路径
5. /lib
6. /usr/lib
7. PKG_CONFIG_PATH

# 库管理工具
- [vcpkg](https://github.com/Microsoft/vcpkg)
    - 不支持版本控制
    - 使用git,cmake每个客户端自动编译
- [Conan](https://github.com/conan-io/conan)

# 编译参数
- \-static 后面的是静态链接库
- \–Bdynamic 后面是动态库
- \-Bstatic 后面是静态库
- \-Wl 后面的参数传递给链接器
- \-Wl,\-\-whole-archive 链接所有函数,不删除未使用的函数(包括三方静态库)
- \-Wl,\-\-no-whole-archive 恢复函数裁剪,删除不使用的函数
- llvm \-ObjC \-all_load \-force_load=xxx\xxx\xx.a
- \-fvisibility=default|internal|hidden|protected 符号默认可见性
- \-finstrument\-functions 在函数调用前后插入函数用来调试__attribute__((no_instrument_function))阻止对这个函数的插入
```c
#include <execinfo.h>
__attribute__((no_instrument_function))
void __cyg_profile_func_enter(void* func, void* frame) {
    fprintf(stderr, "%p %p enter-------\n", func, frame);
    void *buffer[2];
    int count = backtrace(buffer, 2);
    char **infos = backtrace_symbols(buffer, count);
    for (int j = 1; infos != nil && j < count; ++j) {
        fprintf(stderr, "       %s\n", infos[j]);
    }
    free(infos);
    fprintf(stderr, "%p %p enter++++++\n", func, frame);
}
__attribute__((no_instrument_function))
void __cyg_profile_func_exit(void* func, void* frame) {
    fprintf(stderr, "%p %p exit\n", func, frame);
}

gcc/clang

  • gcc -E 打印宏展开代码
  • -FPIC 生成的动态库内存位置无关,即所有程序用同一个动态库内存版本,不加则每个程序将动态库加载进自己的内存空间。当动态库有大量的全局变量时最好是各自一份
  • -ansi: 实现ANSI语言选项。这会关闭与ANSI标准不兼容的GCC的某些“功能”
  • -pedantic: 与-ansi一起使用,这告诉编译器严格遵守ANSI标准,拒绝任何不符合的代码
  • -fms-extensions 允许微软扩展, 这允许结构体内嵌未命名的另一个结构体,-Wno-microsoft-anon-tag-fms-extensions-pedantic
  • lamda 函数 ```C #define lambda(ret_type, …)
    extension
    ({
    ret_type fn VA_ARGS
    fn;
    })

int main(int argc, char argv[]) { int (max) (int, int) = lambda(int, (int x, int y) {return x > y ? x : y; }); int a = 5566, b = 9527; printf(“max(%d, %d) = %d\n”, a, b, max(a, b));

int c = __extension__ 0b101010;
printf("binary const c = %x\n", c);

return 0; } ``` - __builtin_expect                  分支优化判断 - __builtin_constant_p              判断是否静态变量 - __builtin_bswap16|32|64           位反转 - 浮点数默认是double, 末尾f=float,l=long double,q=__float128,fn=_Floatn,fnx=Floatnx,dx=_Decimalx - __builtin_inf                     返回正无穷大  - __builtin_fabs                    绝对值 - __builtin_copysign                拷贝a的符合给b - __builtin_huge_val                正无穷大 - __builtin_inf                     返回溢出 - __builtin_assume_aligned          告知此指针地址已按n字节对齐了 - __builtin_add|sub|mul_overflow    溢出判断 - __builtin_preserve_access_index   字段重定向 ```C struct XXX(old) {
int a; } __attribute__((preserve_access_index));

struct XXX(new) { int b; int a; } attribute((preserve_access_index)); //导出符号表, 会记录a的结构体偏移 int *pa = __builtin_preserve_access_index(&(xxx->a))

- __builtin_popcountl              返回一个数的二进制表示的10进制整数(4->100)
- __builtin_popcount               返回一个数的二进制中1的个数
- __builtin_clz                    返回一个数的二进制高位0的个数
- __builtin_ctz                    返回一个数的二进制低位0的个数
- -ccc-print-phases 打印编译步骤
- -save-temps       保存中间步骤文件

# debug 符号
- stabs,COFF,XCOFF,PE_COFF,OMF,IEEE-695 都未成为标准
- DWARF(Debugging With Arbitrary Record Formats)1998-1999成为标准
- DIE(Debugging Information Entry) 含一个tag表示类型+属性列表,可包含其它DIE
```C
//hello.c
1:int main() {
2:  printf("Hello DWARF!\n");
3:  return 0;
4:}
/*
    DIE compilation Unit:   ->  DIE Subprogram      ->  DIE Base Type 
    Dir = /x/.../samples        Name = main             Name = int
    Name = hello.c              File = hello.c          ByteSize = 4
    LowPC = 0x0                 Line = 1                Encoding = signed integer
    HighPC = 0x2b               Type = int
    Producer = Clang            LowPC = 0x0
                                HighPC = 0x2b
                                External = yes

.debug_abbrev   - .debug_info 中的缩写信息
.debug_aranges  - 地址到编译单元的查找表
.debug_frame    - 调用栈信息
.debug_info     - 主要的dwarf信息
.debug_line     - 行信息
.debug_loc      - 位置信息
.debug_macinfo  - 宏信息
.debug_pubnames - 函数名字到编译单元的查找表
.debug_pubtypes - 类型名字到编译单元的查找表
.debug_ranges   -  地址范围
.debug_str      -  .debug_info 中的字符串
.debug_types    - 类型描述

libdwarf,dwarfdump,readelf 可以读取
*/

clang-format llvm-format

  • clang-format -style=[LLVM Google Chromium Mozilla WebKit file] file指定格式胚子文件
  • clang-format -style=llvm -dump-config > x.clang-format 导出配置也可以保存为x_clang-format
  • clang-format -style=file -style=”{key: value, …}” 使用默认并修改默认值
  • clang-format -style=llvm -i test.c 将格式化后的文件写入原文件 ``` Language:[None|Cpp|Java|JavaScript|ObjC|Proto|TableGen|TextProto] AccessModifierOffset: -4 public、private等的偏移 AlignAfterOpenBracket:[Align|DontAlign|AlwaysBreak] 开括号(开圆括号、开尖括号、开方括号)后的对齐 AlignConsecutiveAssignments: true 连续赋值时,对齐所有等号 AlignConsecutiveDeclarations: true 连续声明时,对齐所有声明的变量名 AlignEscapedNewlines: Right 右对齐逃脱换行的反斜杠 AlignOperands: true 对齐操作符 AlignTrailingComments: true 对齐连续的尾随的注释 AllowAllParametersOfDeclarationOnNextLine: true 允许函数声明的所有参数在放在下一行 AllowShortBlocksOnASingleLine: false 允许短的块放在同一行 AllowShortCaseLabelsOnASingleLine: false 允许短的case标签放在同一行 AllowShortFunctionsOnASingleLine:[None|InlineOnly(在类中)|Empty(空函数)|Inline(在类中,空函数)|All] 允许短的函数放在同一行 AllowShortIfStatementsOnASingleLine: false 允许短的if语句保持在同一行 AllowShortLoopsOnASingleLine: false 允许短的循环保持在同一行 AlwaysBreakAfterDefinitionReturnType:[None|TopLevel|deprecated] 总是在定义返回类型后换行
    AlwaysBreakAfterReturnType:[None|All|TopLevel(顶级函数)|AllDefinitions(所有的定义,不包括声明)|TopLevelDefinitions(所有的顶级函数的定义)] 总是在返回类型后换行 AlwaysBreakBeforeMultilineStrings: false 总是在多行string字面量前换行 AlwaysBreakTemplateDeclarations:MultiLine 总是在template声明后换行 BinPackArguments: true false表示函数实参要么都在同一行,要么都各自一行 BinPackParameters: true false表示所有形参要么都在同一行,要么都各自一行 BreakBeforeBraces:[Attach(始终将大括号附加到周围的上下文)|Linux(除函数、命名空间和类定义外Attach)|Mozilla(除枚举、函数、记录定义外Attach)|Stroustrup(除函数定义、catch、else外Attach)|Allman(总是大括号前换行), GNU(总是在大括号前换行,控制语句的大括号增加缩进)|WebKit(在函数前换行)|Custom(自定义)] 在大括号前换行 BraceWrapping: 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 AfterClass: false class定义后面 AfterControlStatement: false 控制语句后面 AfterEnum: false enum定义后面 AfterFunction: false 函数定义后面 AfterNamespace: false 命名空间定义后面 AfterObjCDeclaration: false ObjC定义后面 AfterStruct: false struct定义后面 AfterUnion: false union定义后面 BeforeCatch: true catch之前 BeforeElse: true else之前 IndentBraces: false 缩进大括号 BreakBeforeBinaryOperators:[None(在操作符后换行)|NonAssignment(在非赋值的操作符前换行)|All(在操作符前换行)] 在二元运算符前换行 BreakBeforeTernaryOperators: true 在三元运算符前换行 BreakBeforeInheritanceComma: false 在继承前换行 BreakInheritanceList:BeforeColon 继承列表换行 BreakConstructorInitializersBeforeComma: false 在构造函数的初始化列表的逗号前换行 BreakConstructorInitializers:BeforeColon 构造列表换行 BreakAfterJavaFieldAnnotations:false 在java注释后换行 ColumnLimit: 200 每行字符的限制,0表示没有限制 CommentPragmas: ‘^ IWYU pragma:’ 描述具有特殊意义的注释的正则表达式,不被分割为多行或以其它方式改变 ConstructorInitializerAllOnOneLineOrOnePerLine: false 构造函数的初始化列表要么都在同一行,要么都各自一行 ConstructorInitializerIndentWidth: 4 构造函数的初始化列表的缩进宽度 ContinuationIndentWidth: 4 延续的行的缩进宽度 Cpp11BracedListStyle: false 去除C++11的列表初始化的大括号{后和}前的空格 DerivePointerAlignment: false 继承最常用的指针和引用的对齐方式 DisableFormat: false 关闭格式化 ExperimentalAutoDetectBinPacking: false 自动检测函数的调用和定义是否被格式为每行一个参数 ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] 需要被解读为foreach循环而不是函数调用的宏 SortIncludes: true 允许排序#include IncludeCategories: 对#include进行排序 数字越小越靠前,未匹配的放最后
    • Regex: ‘^”(llvm|llvm-c|clang|clang-c)/’ Priority: 2
    • Regex: ‘^(<|”(gtest|isl|json)/)’ Priority: 3
    • Regex: ‘.*’ Priority: 1 IndentCaseLabels: false 缩进case标签 IndentWidth: 4 缩进宽度 IndentWrappedFunctionNames: false 函数返回类型换行时,缩进函数声明或函数定义的函数名 KeepEmptyLinesAtTheStartOfBlocks: true 保留在块开始处的空行 MacroBlockBegin: ‘’ 开始一个块的宏的正则表达式 MacroBlockEnd: ‘’ 结束一个块的宏的正则表达式 MaxEmptyLinesToKeep: 1 连续空行的最大数量 NamespaceIndentation:[None|Inner(缩进嵌套的命名空间)|All] 命名空间的缩进 CompactNamespaces 压缩命名空间 ObjCBlockIndentWidth: 4 使用ObjC块时缩进宽度 ObjCSpaceAfterProperty: false 在ObjC的@property后添加一个空格 ObjCSpaceBeforeProtocolList: true 在ObjC的protocol列表前添加一个空格 PenaltyBreakBeforeFirstCallParameter: 19 在call(后对函数调用换行的penalty PenaltyBreakComment: 300 在一个注释中引入换行的penalty PenaltyBreakFirstLessLess: 120 第一次在«前换行的penalty PenaltyBreakString: 1000 在一个字符串字面量中引入换行的penalty PenaltyExcessCharacter: 1000000 对于每个在行字符数限制之外的字符的penalty PenaltyReturnTypeOnItsOwnLine: 60 将函数的返回类型放到它自己的行的penalty PointerAlignment:[Left, Right, Middle] 指针和引用的对齐: ReflowComments: true 允许重新排版注释 SpaceAfterCStyleCast: false 在C风格类型转换后添加空格 SpaceBeforeAssignmentOperators: true 在赋值运算符之前添加空格 SpaceBeforeParens:[Never, ControlStatements, Always] 开圆括号之前添加一个空格 SpaceInEmptyParentheses: false 在空的圆括号中添加空格 SpacesBeforeTrailingComments: 2 在尾随的评论前添加的空格数 即// SpacesInAngles: true 在尖括号的<后和>前添加空格 SpacesInContainerLiterals: true 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 SpacesInCStyleCastParentheses: true 在C风格类型转换的括号中添加空格 SpacesInParentheses: true 在圆括号的(后和)前添加空格 SpacesInSquareBrackets: true 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 Standard:[Cpp03, Cpp11, Auto] 标准 TabWidth: 4 tab宽度 UseTab:[Never, ForIndentation, ForContinuationAndIndentation, Always] 使用tab字符 ```

ar

  • 主参数
    • -d 删除备存文件中的成员文件
    • -m  变更成员文件在备存文件中的次序
    • -p  显示备存文件中的成员文件内容
    • -q  将文件附加在备存文件末端
    • -r  将文件插入备存文件中
    • -t  显示备存文件中所包含的文件
    • -x  自备存文件中取出成员文件
  • 辅参
    • -a <成员文件>  将文件插入备存文件中指定的成员文件之后
    • -b <成员文件>  将文件插入备存文件中指定的成员文件之前
    • -i <成员文件>  将文件插入备存文件中指定的成员文件之前
    • -c  建立备存文件
    • -f  截掉要放入备存文件中过长的成员文件名称
    • -o  保留备存文件中文件的日期
    • -s  若备存文件中包含了对象模式,可利用此参数建立备存文件的符号表
    • -S  不产生符号表
    • -u  只将日期较新文件插入备存文件中
    • -v  程序执行时显示详细的信息
    • -V  显示版本信息

参数解析 getopt函数

  • int getopt(int argc, char * const argv[], const char *optstring);每次处理一个参数,需要循环执行,返回-1结束
  • 执行过程中会先排序,将无参数选项提前,然后是带参数,最后是无关的参数
  • optstring 指定选项,一个字母一个选项,带:表示选项必须带参数,带::表示选项带可选参数
  • 全局变量optarg指向参数,当选项不带参数时为0
  • 全局变量optind 指向下一个要处理的argv位置
  • 全局变量opterr设置为0,则不会在控制台打印错误信息。
  • 全局变量optopt保存错误信息,当错误时返回’?’表示无法解析,返回’:’表示参数错误

注释生成 apple doc 格式

  • @brief 简单描述
  • @discussion 详细描述
  • @param 参数描述
  • @return 返回值描述
  • @warning 警告信息
  • @see 参考某个类或者某个方法
  • @since 从哪个版本开始支持
  • @exception 异常说明

rpm

  • yum -y install rpm-build
  • 所有用到的宏在/usr/lib/rpm/macros里定义
  • spec 配置文件 %开头不需要:二是必须换行输入,可多行,必须在其他:定义后面定义
    • Name 必须 软件包名字 使用%{name}引用
    • Version 必须 软件包版本 使用%{version}引用
    • Release 必须 软件包修订号 使用%{release}引用 Name-Version-Release.rpm
    • License 必须 软件授权方式GPL..
    • Summary 必须 软件包简单描述
    • Disstribution 发行版标识
    • Vendor 软件包发行厂商
    • Packager 软件包打包者
    • URL 软件包的url
    • %description 必须 软件详细描述信息
    • Source 定义打包所需的源码包,可以定义多个,使用%{SOURCE[1…]}调用
    • BuildRoot 定义打包时的工作目录 使用${RPM_BUILD_ROOT}引用 == xxx/BUILDROOT
    • BuildRequires 定义打包时依赖的软件包
    • Build Arch 指编译的目标处理器架构
    • Patch 定义补丁文件,可以定义多个,使用%{Patch[1…]}调用
    • Requires 定义安装时的依赖包,libpng-devel [>= <= > < =] 1.0.20 zlib
    • Provides 指明本软件一些特定的功能,以便其他rpm识别
    • Conflicts 指明冲突与什么包冲突 [>= <= > < =]
    • Obsoletes 指明废弃的内容
    • Group 软件包所属组。必须是系统定义好的组
      • Amusements/Games (娱乐/游戏)
      • Amusements/Graphics(娱乐/图形)
      • Applications/Archiving (应用/文档)
      • Applications/Communications(应用/通讯)
      • Applications/Databases (应用/数据库)
      • Applications/Editors (应用/编辑器)
      • Applications/Emulators (应用/仿真器)
      • Applications/Engineering (应用/工程)
      • Applications/File (应用/文件)
      • Applications/Internet (应用/因特网)
      • Applications/Multimedia(应用/多媒体)
      • Applications/Productivity (应用/产品)
      • Applications/Publishing(应用/印刷)
      • Applications/System(应用/系统)
      • Applications/Text (应用/文本)
      • Development/Debuggers (开发/调试器)
      • Development/Languages (开发/语言)
      • Development/Libraries (开发/函数库)
      • Development/System (开发/系统)
      • Development/Tools (开发/工具)
      • Documentation (文档)
      • System Environment/Base(系统环境/基础)
      • System Environment/Daemons (系统环境/守护)
      • System Environment/Kernel (系统环境/内核)
      • System Environment/Libraries (系统环境/函数库)
      • System Environment/Shells (系统环境/接口)
      • User Interface/Desktops(用户界面/桌面)
      • User Interface/X (用户界面/X窗口)
      • User Interface/X Hardware Support (用户界面/X硬件支持)
    • 脚本
      • %prep 预处理脚本 %setup %patch %configure 是预定义宏
        • %setup 不加任何选项,解压源码。
        • %setup -n newdir 将源码解压在newdir目录。
        • %setup -c 解压缩之前先产生目录。
        • %setup -b num 将第num个source文件解压缩。
        • %setup -T 不使用default的解压缩操作。
        • %setup -T -b 0 将第0个源代码文件解压缩。
        • %setup -c -n newdir 指定目录名称newdir,并在此目录产生rpm套件。
        • %patch[n] 打补丁
        • %configure 执行源码的configure 并使用/usr/lib/rpm/marcros定义的参数
        • shell command
      • %build 开始构建包
        • 默认使用make /usr/lib/rpm/marcros定义的参数
        • $RPM_OPT_FLAGS 引用/usr/lib/rpm/marcros定义的参数
        • shell command
      • %install 安装到虚拟目录 预定义宏%makeinstall 安装支持 autoconf 的软件
      • %clean 清理临时文件
      • %pre rpm安装前执行的脚本
      • %post rpm安装后执行的脚本
      • %preun rpm卸载前执行的脚本
      • %postun rpm卸载后执行的脚本
      • %files 定义那些文件或目录会放入rpm中,不能用绝对目录%{_bindir} %{_libdir} %{_datadir} %{_includedir}
        • %defattr (mode,owner,group)指定包装文件的属性
        • %exclude 列出不想打包到rpm中的文件,指定不存在的文件会报错
      • %changelog 变更日志 ```shell cd xx cat » xx.spec «EOF %define _prefix /usr/local/nginx //预定义的prefix目录 %define _logpath /var/log/weblog //预定义日志目录 Name: nginx Version: 1.12.1 Release: 1%{?dist} Summary: The Nginx HTTP and reverse proxy server Group: Applications/System License: GPLv2 URL: https://nginx.org Packager: Atlantis XXX@XXX.com Vendor: XXX-XXX Source0: %{name}-%{version}.tar.gz //引用的源码文件 Source1: nginx.conf //引用配置文件 Source2: nginx //引用System-V风格的Service服务 Source3: nginx.logrotate //引用日志轮转的配置文件 BuildRoot: %_topdir/BUILDROOT //虚拟根目录 Requires(post): systemd-units Requires(preun): systemd-units Requires(postun): systemd-units Requires: libxslt-devel,openssl-devel,pcre-devel //所依赖的软件包

%description NGINX is the heart of the modern web, powering half of the world’s busiest sites and applications. The company’s comprehensive application delivery platform combines load balancing, content caching, web serving, security controls, and monitoring in one easy-to-use software package.

%prep //编译前准备工作,这里指定的就是Setup,有条件也可以指定编译器 %setup -q

%build //编译参数,这个看到这里的人基本都懂,没啥讲的,最后一个参数可以使用并行编译: make -j 6 ./configure –user=nginx –group=nginx –prefix=%{_prefix} –http-log-path=%{_logpath}/access.log
–error-log-path=%{_logpath}/error.log –pid-path=/var/run/nginx.pid –with-http_dav_module
–with-http_flv_module –with-http_realip_module –with-http_addition_module –with-http_xslt_module
–with-http_sub_module –with-http_random_index_module –with-http_degradation_module
–with-http_secure_link_module –with-http_gzip_static_module –with-http_ssl_module
–with-http_stub_status_module –with-pcre –with-threads –with-stream –with-ld-opt=-Wl,-E make %{?_smp_mflags}

%install //安装步骤 rm -rf %{buildroot} //保证虚拟根的干净 make install DESTDIR=%{buildroot} //install 到虚拟根 %{__install} -p -d -m 0755 %{buildroot}%{_logpath} //定义一个日志目录并赋予其权限,这个文件会在编译时自动生成,因此要声明 %{__install} -p -D -m 0644 %{SOURCE1} %{buildroot}%{_prefix}/conf/nginx.conf //复制SOURCE1中的文件到虚拟根中 %{__install} -p -D -m 0755 %{SOURCE2} %{buildroot}/etc/rc.d/init.d/nginx //复制SOURCE2中的文件到虚拟根中 %{__install} -p -D -m 0644 %{SOURCE3} %{buildroot}%{_prefix}/conf/nginx.logrotate //复制SOURCE3中的文件到虚拟根中 install -D -m 644 nginx.service $RPM_BUILD_ROOT/usr/lib/systemd/system/nginx.service //

%pre //安装前准备操作 if [ $1 == 1 ]; then // 这里的1为安装;0为卸载 /usr/sbin/useradd -r nginx -s /sbin/nologin 2> /dev/null fi

%post //安装后准备操作 if [ $1 == 1 ]; then echo “export PATH=/usr/local/nginx/sbin:$PATH” » /etc/profile source /etc/profile cp %{_prefix}/conf/nginx.logrotate /etc/logrotate.d/nginx fi

%preun //卸载前准备操作 if [ $1 == 0 ]; then /etc/init.d/nginx stop 2>&1 /dev/null /usr/sbin/userdel -r nginx 2> /dev/null fi

%postun if [ $1 == 0 ]; then //卸载后准备操作 rm -f /etc/logrotate.d/nginx fi

%clean rm -rf %{buildroot}

%files //定义rpm包安装时创建的相关目录及文件。在该选项中%defattr (-,root,root)一定要注意。它是指定安装文件的属性,分别是(mode,owner,group),-表示默认值,对文本文件是0644,可执行文件是0755。 %defattr(-,root,root,0755) %{_prefix} %dir /var/log/weblog %attr(644,root,root) %{_prefix}/conf/nginx.conf %attr(755,root,root) /etc/rc.d/init.d/nginx

%changelog

  • Fri Feb 22 2019 XXX@XXX - 1.12.1-3
  • Initial Version
  • Update Installtion
  • Add Logrotate Feature
  • Fix Uninstall Bug With logrotate

End Of nginx.spec

EOF rpmbuild –define “_topdir pwd” -ba xx.spec #生成BUILD编译目录 BUILDROOT生成目录 RPMS最终rpm包 SOURCES源码 SPECS存spec文件 SRPMS 源rpm包 rpm -qpl xxxx.rpm #查看内容


# scan-build
- scan-build [options] cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=on [build options] .
- scan-build [options] make [build options]
- cmake -DCMAKE_C_COMPILER=ccc-analyzer -DCMAKE_CXX_COMPILER=c++-analyzer
- options
    - -analyze-headers
    - -o <output location>    默认输出到临时目录如: /tmp
    - -k --keep-going         强制编译错误继续编译
    - -plist                  生成 .plist 默认为html
    - --html-title [title]
    - -plist-html             html 和 plist 文件都生成
    - --status-bugs           默认返回编译器返回码, 设置后会判断编译错误
    - --use-cc [compiler path]使用的C编译器路径
    - --use-c++ [compiler path]使用的C++编译器路径
    - -v                      报告详细程度, 最多-v -v -v三次
    - -no-failure-reports     禁止报告编译失败和分析失败的信息
    - -stats                  生成统计信息
    - -maxloop <loop count>   函数最多分析次数默认是4,数字越大覆盖率越好
    - -internal-stats         生成统计信息
    - --use-analyzer [Xcode|path to clang] 默认使用当前目录下的clang
    - --keep-empty            无任何错误报告也不要删除编译目录
    - --override-compiler     使用使用ccc-analyzer
    - -load-plugin [plugin library] 加载扩展插件
    - -enable|disable-checker [checker name],...
        checker name|default|作用
        :--|--:|:--:
        alpha.core.BoolAssignment|NO|bool值赋非0 1值      
        alpha.core.CastSize|NO|当调用malloc type T, T有不同的size时
        alpha.core.CastToStruct|NO|检查强制转换为结构体
        alpha.core.FixedAddr|NO|检查给指针赋值了固定值
        alpha.core.IdenticalExpr|NO|警告在运算中使用了相同表达式
        alpha.core.PointerArithm|NO|检测数组越界
        alpha.core.PointerSub|NO|检测在两个不同内存块上的指针算法
        alpha.core.SizeofPtr|NO|检测表达式中对指针做sizeof操作
        alpha.cplusplus.NewDeleteLeaks|NO|检测内存泄漏
        alpha.cplusplus.VirtualCall|NO|在构造和析构函数中调用虚函数
        alpha.deadcode.IdempotentOperations|NO|警告非幂等运算
        alpha.deadcode.UnreachableCode|NO|警告无用代码
        alpha.osx.cocoa.Dealloc|NO|警告Objective-C中未正确实现的dealloc函数
        alpha.osx.cocoa.DirectIvarAssignment|NO|检测实例变量的直接赋值
        alpha.osx.cocoa.DirectIvarAssignmentForAnnotatedFunctions|NO|检测设置objc_no_direct_instance_variable_assignment的函数直接赋值
        alpha.osx.cocoa.InstanceVariableInvalidation|NO|检测设置objc_instance_variable_invalidator实例变量是否失效
        alpha.osx.cocoa.MissingInvalidationMethod|NO|检测即时变量中包含非即时函数调用
        alpha.osx.cocoa.MissingSuperCall|NO|警告Objective-C函数重载未调用super方法   
        alpha.security.ArrayBound|NO|检测数组越界的旧插件
        alpha.security.ArrayBoundV2|NO|检测数组越界的新插件
        alpha.security.MallocOverflow|NO|检测malloc()参数越界
        alpha.security.ReturnPtrRange|NO|检测返回指针指向栈地址
        alpha.security.taint.TaintPropagation|NO|生成其它检测程序使用的信息
        alpha.unix.Chroot|NO|检测使用chroot错误
        alpha.unix.MallocWithAnnotations|NO|检测内存多次释放、释放后使用及内存泄漏(假设所有内存必须释放)
        alpha.unix.PthreadLock|NO|检测死锁
        alpha.unix.SimpleStream|NO|检测IO流函数错误用法
        alpha.unix.Stream|NO|检测IO处理
        alpha.unix.cstring.BufferOverlap|NO|检测内存缓冲区使用越界
        alpha.unix.cstring.NotNullTerminated|NO|检测无结束符的字符串                              
        alpha.unix.cstring.OutOfBounds|NO|检测字符串越界访问
        core.CallAndMessage|YES|检测函数调用或Objective-C message 逻辑错误
        core.DivideZero|YES|检测被0除
        core.DynamicTypePropagation|YES|生成动态类型信息
        core.NonNullParamChecker|YES|检测将NULL传给引用或参数标记为nonnull
        core.NullDereference|YES|检测空指针
        core.StackAddressEscape|YES|检测栈内存地址逃逸
        core.UndefinedBinaryOperatorResult|YES|检测位运算符的未定义结果
        core.VLASize|YES|检测未定义或0大小的变长数组
        core.builtin.BuiltinFunctions|YES|评估编译器函数
        core.builtin.NoReturnFunctions|YES|评估永久阻塞函数调用
        core.uninitialized.ArraySubscript|YES|检测数组索引未初始化
        core.uninitialized.Assign|YES|检测未初始化
        core.uninitialized.Branch|YES|检测未初始化的分支条件
        core.uninitialized.CapturedBlockVariable|YES|检测Objective-C未初始化的block
        core.uninitialized.UndefReturn|YES|检测返回值未初始化
        cplusplus.NewDelete|YES|检测多次释放或释放后使用,或未初始化实例
        deadcode.DeadStores|YES|检测变量赋值后不再使用
        debug.ConfigDumper|NO|转储配置表
        debug.DumpCFG|NO|输出控制流图
        debug.DumpCallGraph|NO|输出调用流图
        debug.DumpCalls|NO|输出递归调用
        debug.DumpDominators|NO|输出优化树
        debug.DumpLiveVars|NO|输出对象生命周期
        debug.DumpTraversal|NO|打印引擎遍历程序分支时使用的变量值
        debug.ExprInspection|NO|打印表达式分析结果
        debug.Stats|NO|输出统计信息
        debug.TaintTest|NO|标记有问题的符号
        debug.ViewCFG|NO|使用GraphViz显示控制流图
        debug.ViewCallGraph|NO|使用GraphViz显示调用流图            
        debug.ViewExplodedGraph|NO|使用GraphViz显示分解图
        llvm.Conventions|NO|检测llvm代码ABI
        osx.API|NO|检测apple API使用问题
        osx.SecKeychainAPI|NO|检测Secure Keychain APIs使用问题
        osx.cocoa.AtSync|NO|检测@synchronized同步使用nil对象
        osx.cocoa.ClassRelease|NO|检测引用计数 'retain', 'release', or 'autorelease' directly to a Class
        osx.cocoa.IncompatibleMethodTypes|NO|警告不兼容的Objective-C签名
        osx.cocoa.Loops|NO|检测Objective-C loops类型
        osx.cocoa.NSAutoreleasePool|NO|警告NSAutoreleasePool最佳实践
        osx.cocoa.NSError|NO|检测NSError参数
        osx.cocoa.NilArg|NO|检测禁用nil参数的函数,参数为nil
        osx.cocoa.NonNilReturnValue|NO|检测非空返回值约定
        osx.cocoa.RetainCount|NO|检测引用计数错误
        osx.cocoa.SelfInit|NO|检测构造函数中self是否正确初始化
        osx.cocoa.UnusedIvars|NO|检测未使用的私有变量
        osx.cocoa.VariadicMethodTypes|NO|检测将非Objective-C对象传给只接受Objective-C对象
        osx.coreFoundation.CFError|NO|检测CFError参数      
        osx.coreFoundation.CFNumber|NO|检测CFNumberCreate使用是否正确
        osx.coreFoundation.CFRetainRelease|NO|检测CFRetain/CFRelease/CFMakeCollectable的参数
        osx.coreFoundation.containers.OutOfBounds|NO|检测CFArray索引越界
        osx.coreFoundation.containers.PointerSizedValues|NO|检测CFArray|CFDictionary'|CFSet初始化的size值
        security.FloatLoopCounter|NO|使用浮点数作为循环计数
        security.insecureAPI.UncheckedReturn|YES|警告未使用的函数返回值
        security.insecureAPI.getpw|YES|使用getpw函数时警告
        security.insecureAPI.gets|YES|使用gets函数时警告
        security.insecureAPI.mkstemp|YES|警告mkstemp函数参数少于6个字符
        security.insecureAPI.mktemp|YES|使用mktemp函数时警告
        security.insecureAPI.rand|NO|使用'rand', 'random'时警告
        security.insecureAPI.strcpy|NO|使用'strcpy' 'strcat'函数时警告
        security.insecureAPI.vfork|YES|使用vfork函数时警告
        unix.API|YES|检测UNIX/Posix函数调用错误
        unix.Malloc|YES|检测多重是否、内存泄漏、释放后使用
        unix.MallocSizeof|YES|检测错误的sizeof malloc调用
        unix.MismatchedDeallocator|YES|检测不匹配的deallocators
        unix.cstring.BadSizeArg|YES|检测c字符串传入的size是否不正常
        unix.cstring.NullArg|YES|检测传入NULL到cstring

# gcov
- 执行流![](../img/c\c++/gcov-logic.png)
- flag=-fprofile-arcs -ftest-coverage  link=gcov
- make -> run -> gcov -> lcov -> genhtml

# llvm-cov
- -fprofile-instr-generate -fcoverage-mapping -mllvm -runtime-counter-relocation
- make
- LLVM_PROFILE_FILE="xxx.profraw" xxxx   profile配置输出内容,执行程序
    - %p  代表进程ID
    - %h  代表主机名称
    - %t  输出临时目录
    - %Nm N=[1 9]缓冲池数量
    - %c  合并历史数据, 多次运行或崩溃后继续
- llvm-profdata merge -sparse xx.profraw yy.profraw zz.profdata -o xxx.profdata
    - -sparse 会无法生成调用图
- llvm-cov show xxx -instr-profile=xxx.profdata 直接命令行显示代码具体覆盖率信息
    - -show-line-counts-or-regionsllvm-cov
    - -show-branches=count--show-expansions
- llvm-cov report xxx -instr-profile=xxx.profdata 生成对文件的统计信息
- readelf -S /x/x | grep .debug 判断是否debug版本


# 没用的知识
```c
#if 'A' == '\301'
# define SQLITE_EBCDIC          1               //IBM商用机打孔机相同的编码
#else
# define SQLITE_ASCII           1
#endif
//int h = 0-9a-fA-F 转 int
#ifdef SQLITE_ASCII
    (((h) + 9 * (((h) & 0x40) >> 6)) & 0x0F)
#endif
#ifdef SQLITE_EBCDIC
    (((h) + 9 * ( 1 & (~((h) >> 4)))) & 0x0F)
#endif