hw01
hw01 copied to clipboard
高性能并行编程与优化 - 第01讲回家作业
奇怪,我在win上遇到的问题是exe和stbiw的lib不在同一个文件夹: main.exe stbiw/libstbiw.dll stbiw/libstbiw.dll.a 会报找不到。但只要把这俩lib拷贝出来就可以了。是因为我用的mingw吗?有啥办法可以不用手动拷?按道理子目录不是通过add_subdirectory加到里面了吗?
环境:win10+cmake+mingw 我可以编过但是动态库跑的时候在stbiw文件夹下面所以exe找不到啊啊啊啊啊啊啊啊
A文件要用B文件实现的函数,需要在A文件中对函数进行声明 所以为了方便B文件实现的函数被多个别的文件使用,可以将函数的声明和实现分离 需要用到的文件直接include函数的声明即可 stb下的库都是单文件库 为了让声明和实现分离,方便多个文件使用,stb下的库都会约定一个宏`#if define XXXXX` 当这个宏被定义时,后面的函数实现部分才会被编译 题目要求定义stbiw这个库,那么就需要函数的实现,在stdiw文件下新建一个源文件,在include stb_image_write之前define其约定的宏,该源文件就可以在编译时包含声明+实现,从而用该文件生成所需要的库 为了stb_image_write.h能被找到,在子目录的cmakelist添加到头文件搜索路径并设为 PUBLIC 即可,这样子目录和主目录的文件都可以通过 include到stb_image_write.h
完成第一个实验,学会了PR。
- 当定义`STB_IMAGE_WRITE_IMPLEMENTATION`,`stb_image_write.h`就会添加函数定义,不然只有函数申明。`C++`允许多次申明,所以只要在引用`stb_image_write.h`头文件之前`#define STB_IMAGE_WRITE_IMPLEMENTATION`,后面再使用`stb_image_write.h`的文件不能再定义`STB_IMAGE_WRITE_IMPLEMENTATION`,所以在`./stbiw/CMakeList.txt`的`target_complie_definitions()`中使用`PRIVATE`。 - 因为除`stbiw`静态库中使用`stb_image_write.h`,之后使用`stbiw`库的`main`也要使用。所以在`./stbiw/CMakeList.txt`的`target_include_directories()`中使用`PUBLIC`。 - 添加`stbiw.cc`为了可以生成库。
一些c/cpp的库由头文件和cpp文件组成,头文件中写声明,而cpp文件中写定义。编译时指定头文件路径,并 编译出静态库进行链接(或者运行时动态链接)即可。 另一种cpp库为header only,即只有头文件。但是普通的函数定义不能放在头文件中,因为如果在多个cpp文件 中include这个头文件就会造成ODR violation。为了解决这个问题: - 只在头文件中定义模板函数、内联函数(比如STL) - 使用类似`STB_IMAGE_WRITE_IMPLEMENTATION`这样的宏,由这个宏包裹起来的代码为函数的实现,不包裹起来的代码为声明,所以如果我们只在一个cpp文件中定义这个宏,相当于函数的实现就只会出现一次,就不会出现重复定义的问题。 ## 方法2 对于stb库,我们也可以把这个头文件中的函数定义部分抽出来放在子模块文件夹里的cpp文件中 ```cpp // stbiw/stb_def.cpp #define STB_IMAGE_WRITE_IMPLEMENTATION #include ``` 然后可以在`stbiw/CMakeLists.txt中将stbiw编译成一个静态库 ```cmake add_library(stbiw STATIC stb_def.cpp) target_include_directories(stbiw PUBLIC .) ``` 使用这种方法,我们编译出了一个静态库,只需要链接进main即可,就不需要寻找一个合适的cpp文件把宏定义放进去了...
我尝试了直接编译会返回undefined reference 然后把stbi_write_png的定义拷贝到cpp里面返回0编译通过 加入 STB_IMAGE_WRITE_IMPLEMENTATION 后会返回 multiple definition 也就是说加入了 STB_IMAGE_WRITE_IMPLEMENTATION这个的cpp文件会变成定义的文件 target_compile_definitions这个,好像target有多个cpp文件并都引用了stb_image_write.h不管用 PUBLIC PRIVATE都会报错
1. 新建一个.cpp文件,然后只include对应的.h文件 2. 增加lib的编译选项,而且设置为私有的,这是因为如果传播的话,会导致其他依赖.h的文件都会看到实现,则link的时候会有多个符号重复 3. 同时target_include_directories中要设置为PUBLIC,使得其他库可以直接使用include 定义了STB_IMAGE_WRITE_IMPLEMENTATION这个宏,可以控制include的文件是只能看到定义还是可以看到实现。从而避免 link的时候出现对个相同符号的问题。
为什么stbi要这样设计 首先我理解的“这样”指的是header only,且当引用时需要定义一个STB_IMAGE_WRITE_IMPLEMENTATION这样的宏。 header only的好处是跨平台+使用方便,为了实现header only就需要把函数实现写在头文件中,但是为了避免多次定义,就需要加入STB_IMAGE_WRITE_IMPLEMENTATION这样的宏。
# HW1 Report ## 步骤 1. 在stbiw中添加stb_image_write.cpp文件,include对应头文件并添加开关宏。 2. 在CMakeLists.txt中添加stbiw的静态库,并指定stbiw的include路径。 ## 解释 1. 编译时以cpp文件为单位进行编译,只有头文件无法编译,所以需要在stbiw中添加对应的.cpp文件以编译静态库。 2. stb_image_write.h的内容大致为: ```cpp #ifndef INCLUDE_STB_IMAGE_WRITE_H //声明 #endif #ifdef STB_IMAGE_WRITE_IMPLEMENTATION //定义 #endif ``` 所以需要添加STB_IMAGE_WRITE_IMPLEMENTATION来开启对应部分的实现。由于实现部分并没有类似的头文件保护,如果多处添加该宏就会重定义。