基于vs的RTKLIB2.4.3编译学习历程及经验分享

基于VS2008利用rtklib开源代码处理GPS以及北斗数据详解

1、在vs中新建一个控制台项目(含预编译头);

 

2、在建好的项目中添加rtklib.h以及需要用到的source文件(.c文件),然后将.c改为.cpp并在每个文件首句增加一行#include "stdafx.h",当然在stdafx.h文件中添加#include "rtklib.h"; 这样编译基本可以通过了;

 

3、一般而言,我们不会需要用到rtklib程序集中的所有文件,只是需要部分。比如我需要用到其中的pntpos这个标准单点定位函数,这个时候就需要添加该函数所在实现文件(pntpos.c)。于是添加了这个文件。但是一般而言,只添加这一个可能不能解决问题,因为rtklib的各个文件之间并不是完全独立,pntpos文件中某些函数可能会调用到其他文件中实现的函数。于是需要再把相关文件添加到工程中。对于这个问题,可以根据自己添加的文件,编译时候的提示,依次添加进来相应文件。这样可以解决fatal error的问题;

 

4、在添加完成后,可能会遇到一些其他问题。主要问题有:

a.关于某些地方数组越界或为空(主要是glonass),这个时候,查看rtklib.h头文件,可以发现关于系统启用的#define语句,其中除GPS系统外,其他系统数目都是0,解决的办法主要是注释掉这个判断语句。注释掉rtklib.h文件的自第146行后开始的关于启用其他卫星导航系统的语句,如GLONASS:

//#else

//#define MINPRNGLO   0

//#define MAXPRNGLO   0

//#define NSATGLO     0

//#define NSYSGLO     0

//#endif

 

b.关于很多地方会出现const char*char*的不能转化问题,这个很简单,在相应地方进行强制转化就行。

c.还存在字符集采用的问题,这个只需要在项目属性中使用多字节字符集即可(见下图)。

d.关于某些函数存在未实现的问题,这个时候,可以网上直接搜索那些没有实现的函数,进行替换,或是直接屏蔽掉。

 

rtklib中代码的添加工作基本就这些问题,解决后应该就可以使用了

 

 

相关文章地址:https://www.cnblogs.com/DKSoft/p/4677381.html

这篇介绍了VS2008平台下创建一个C++控制台程序,编译rtklib源码的过程,创建时含预编译头,另外麻烦的将.c文件都改为.cpp文件,还取巧通过注释程序的方法避免一些问题,总的来说没有针对性解决问题,借鉴意义不大。

 

 

学习rtklib时,作者在manual中说过,可以用gcc重建CUI程序。因此选择Visual Studio来重建,VS比C++ Builder好用,且网上的资源也多得多。

1. 首先在vs2013中新建一个win32的dll项目,取消预编译头。,将rtklib下src源码放到工程路径***意不是工程组所在路径),如E:\Projects\rtklib-rebuild\src

2. 在项目上添加一个文件夹rtklibsrc然后在文件夹上【添加现有项目】把src中另外的源文件下文件加入工程。在rtklib-rebuild下建立rcv文件夹把原src\rcv下面的文件也添加到工程。创建的工程如下图所示:

                                              基于vs的RTKLIB2.4.3编译学习历程及经验分享

 

然后我们尝试执行编译。

首次编译会与很多错误,我第一次编译时提示了大量的:无法打开包括文件:“rtklib.h”的错误,这是因为没有将rtklib.h头文件的目录包含在项目里的缘故。

解决思路就是将以下路径加入到include目录下(在项目上右键->配置属性->VC++目录->包含目录Include Path选择rtklib.h所在的目录即可)。

 

再次编译,上述错误不再提示。但还存在以下三个错误:

基于vs的RTKLIB2.4.3编译学习历程及经验分享

 

首先是一个这样的错误:

error C2466: 不能分配常量大小为0的数组    x:\xxxx\rtklibhelper\rtklibsrc\rinex.c

 

这个错误我们来看一下, 在[MAXPRNGLO]上面按F12,看他的定义处。

基于vs的RTKLIB2.4.3编译学习历程及经验分享

这个常量为0,那么不能进行编译,我们需要在预编译器里面加入 ENAGLO

 

网上的教程是:项目上右键->c/c++  ->预处理器->添加ENAGLO。

 

再次编译发现上述问题确实消失了。但是会出现以下新的问题。。。。。。

基于vs的RTKLIB2.4.3编译学习历程及经验分享

 

error LNK2019: 无法解析的外部符号 _settspan,该符号在函数 _postpos 中被引用    x:\xxxx\ xxxx \postpos.obj  

 error LNK2019: 无法解析的外部符号 _showmsg,该符号在函数 _convrnx 中被引用    x:\xxxx\ xxxx \convrnx.obj

error LNK2019: 无法解析的外部符号 [email protected],该符号在函数_tickget 中被引用   x:\xxxx\ xxxx \rtkcmn.obj   

error LNK2019: 无法解析的外部符号 [email protected],该符号在函数 _accept_nb 中被引用    x:\xxxx\ xxxx \stream.obj 

 

解决思路可通过在添加附加库[连接器->输入->附加依赖库]添加winmm.lib, ws2_32.lib ;在预处理器里面加入DLL,来解决此问题。

 

 

最终其预编译器定义中应包含:

Win32

_CRT_SECURE_NO_WARNINGS 
_WINSOCK_DEPRECATED_NO_WARNINGS 
ENAGLO 
DLL

但我尝试上述方法问题并没有得到解决。。。。。。

另有网友指出:

1)预编译器定义的问题。

RTKLIB中为了适应不同的应用需求,定义了诸多的宏,常见的包括ENAGLO,ENACMP ,_CRT_SECURE_NO_WARNINGS,_WINSOCK_DEPRECATED_NO_WARNINGS等。这些预编译器定义存在的根本目的是为了控制代码编译的走向,以确保功能的实现,为此我们需要详细了解各个宏定义的存在的目的。例如,_CRT_SECURE_NO_WARNINGS存在的目的是确保strcmp等VS认为不安全的函数的有效执行。_WINSOCK_DEPRECATED_NO_WARNINGS存在的目的是确保通信sock函数的有效执行。ENAGLO,ENACMP,WIN_DLL,TRACE存在的目的是确保与GLONASS、与北斗、与windows动态库编译、与TRACE信息输出相关的函数的有效执行。通过合理的预编译器定义,我们可以得到不同功能的RTKLIB动态库。

(2)附加依赖项的问题

前一个作者为了规避"找不到error LNK2019: 无法解析的外部符号…"的问题,选择了在添加附加库[连接器->输入->附加依赖库]中添加winmm.lib, ws2_32.lib。虽然可以解决问题,但是不够直观,很容易被其他开发人员忽略。此作者认为直接在头文件代码中添加#pragma comment(lib, "winmm.lib")和#pragma comment(lib, "ws2_32.lib")更为直观明了,一劳永逸。

 

但我尝试之后还是不行。。。。。。

 

https://www.cnblogs.com/DKSoft/p/4677381.html

这篇文章目的在于将rtklib中的源码封装为dll用来供其他C程序调用,不知道与我们创建c++控制台项目或者其他win32项目的结果有什么区别。按照几篇相似文章的介绍,error LNK2019: 无法解析的外部符号问题一直无法解决,可能是我没有创建dll项目的原因。

 

上述调试都是基于将rtklib源码封装为一个动态库供调用。无问题后有作者基于这个库写了段小的调用程序:

在完成了RTKLIB动态库编译后,利用动态库可构建简单的RTCM数据读取的Demo。Demo程序读取保存的实时RTCM观测信息并输出观测值文件、导航文件以及TRACE日志信息。Demo代码如下:

 

 1 #include "rtklib.h"

 2 int main()

 3 {

 4     char ifile[1024] = "C:xxx.rtcm";    

 5     char ofile[9][1024] = { "", "", "", "", "", "", "", "" };

 6     char *pofile[9] = { "" };

 7     char tracefile[1024] = "";

 8     int format = STRFMT_RTCM3;

 9  

10     double ep_rtcm[6] = { 2017, 9, 4, 14, 00, 00 };    

11     gtime_t time_rtcm = epoch2time(ep_rtcm);    

12     

13     rnxopt_t opt = { 0 };    

14     opt.tint = 0.00;

15     opt.tunit = 86400;

16     opt.rnxver = 3.02;

17     opt.navsys = 37;

18     opt.obstype = OBSTYPE_ALL;

19     opt.freqtype = 0x03;

20     opt.scanobs = 1;

21     opt.outiono = 1;

22     opt.outtime = 1;

23     opt.trtcm = time_rtcm;

24  

25     strcpy(ofile[0], ifile);

26     strcat(ofile[0], ".obs");

27  

28     strcpy(ofile[1], ifile);

29     strcat(ofile[1], ".nav");

30  

31     strcpy(tracefile, ifile);

32     strcat(tracefile, ".trace");

33     traceopen(tracefile);

34     tracelevel(5);     

35     for (int i = 0; i < 9; i++) {

36         pofile[i] = malloc(sizeof(char) * 1024);

37         memcpy(pofile[i], &ofile[i], 1024);

38     }    

39     if (convrnx(format, &opt, ifile, pofile)) printf("\n数据转换成功!\n");    

40     traceclose();

41     getchar();

42     return 0;

43 }

 

 

 

在调试Demo过程中,笔者发现RTKLIB库仍存在两个问题:

(1)添加TRACE预编译器定义后,软件运行到scan_obstype函数的trace(3,"scan_obstype: nf=%s, opt=%s\n",nf,opt)语句时会提示内存出错,调试后发现该语句中nf的输出类型出错,应将"%s"更改为"%d",即trace(3,"scan_obstype: nf=%d, opt=%s\n",nf,opt)。这反映了RTKLIB原始编码系统环境与VS IDE的差异,后续应用库文件时需要多加注意。

(2)convrnx函数在执行完成退出动态库回到主函数main时,Debug模式下会弹出"Run-Time Check Failure #2 - Stack around the variable 'opt_' was corrupted."异常。Release模式下不弹出该异常。网络上关于该异常主体上认为时由于内存越界造成的,笔者暂未找出opt_变量越界的原因,后续会做深入研究。该异常的最快捷的解决方案时将"project->配置属性->c/c++->代码生成->基本运行时检查"改为"默认值"即可。

 

 

 

RTKLIB编译—形成GNSS定位开源库,RTKLIB开源库有着强大的GPS数据实时和后处理功能,RTKLIB还提供了很多底层的函数,因此我们可以考虑采用直接对源码进行编译输出标准DLL的方式供C调用。便编译平台选择VS,RTKLIB库用的是网上开源的rtklib_2.4.3版本,编译的项目采用“相对路径”,即工程可移植到任何地方,方便以后使用。

RTKLIB的下载地址为:http://www.rtklib.com/

 

1、新建工程。首先,我们在VS2012下先新建一个win32dll项目(空项目)

                                              基于vs的RTKLIB2.4.3编译学习历程及经验分享

 

2、复制库文件。把在github上下载的rtklib2.4.3里的 “src文件夹文件复制到刚刚建立的RTKLIB工程项目文件所在目录下

3、添加库文件。为了与库文件结构保持一致,我们首先源文件文件夹,右击》添加》新建筛选器,接下来先添加头文件rtklib.h;然后是源文件》添加》现有项(添加除rtklib.h所有源文件,)创建“rcv”子文件夹并添加“src/rcv”目录下的所有源文件

4、初步编译解决方案管资源理器下,右击“RTKLIB”项目》生成,进行编译。因为RTKLIB是在C++ Builder编译器下写的,但是我们现在用VS进行编译,会出现一堆的错误,现在我们就一个个来解决。

 

错误类型1error C4996: 'strncpy': This function or variable may beunsafe. Consider using strncpy_s instead. To disable deprecation, use_CRT_SECURE_NO_WARNINGS. See online help for details.

解决:这是由于函数安全性问题,编译器已经给出建议,添加预编译指令【_CRT_SECURE_NO_WARNINGS】。我们打开调试下的项目属性,然后在 配置属性 -> C/C++ -> 预处理器 -> 预处理器定义 -> 编辑。在下面添加上【_CRT_SECURE_NO_WARNINGS】

同样类似上面的错误,解决方法也类似,同样在预处理器定义-> 编辑。在下面添加上【_WINSOCK_DEPRECATED_NO_WARNINGS

错误类型2 error C2466: 不能分配常量大小为 0 的数组 

解决:这个主要是编译器的问题,用g++就没有问题,在vc中定义数组,需要一个常量值。

我们双击此错误,在有问题的数组定义处,按F12,看到数组大小定义的确实是0。我们像上面一样在预处理器定义里面加入【ENAGLO可解决此问题。

 

错误类型3error C1083: 无法打开包括文件:“rtklib.h”: No such file ordirectory    

解决:这是因为rcv里的文件找不到rtklib.h这个头文件。我们继续在项目属性里,在配置属性-> C/C++ 常规-> 附加包含目录-> 编辑。在上面添加rtklib.h的相对路径(使用相对路径,工程才可以移植到任何地方,否则,换个目录路径,还是会提示此错误)在项目里的src找到rtklib.h并查看它的绝对路径在属性界面下的附加包含目录下,添加:【.\src

错误类型4error LNK2019: 无法解析的外部符号 _showmsg,该符号在函数 _convrnx 中被引用  

解决:一查showmsg这个函数如果在DLL中需要自己定义,rtklib里面已经做好了处理需要在预处理器里面加入【DLL】即可,我们找到之前预处理器定义处,在下面添加【DLL】,再找到项目属性,在配置属性 -> 链接器 -> 输入 -> 附加依赖项里添加【winmm.lib】和 【ws2_32.lib】

部分警告处理大多数是什么类型转换上的Warning,暂时没有影响,暂不处理

 

同样按照这篇文章的操作步骤仍然无法成功将rtklib编译为一个dll库文件,问题仍出在:

基于vs的RTKLIB2.4.3编译学习历程及经验分享

看了几篇文章试了几种方法这个问题一直无法得到解决。

经过与文章四对比发现,解决这个问题的关键就在于将RTKLIB-rtklib_2.4.3\app\rnx2rtkp文件夹下的rnx2rtkp.c文件放到项目的src文件夹下并加入到工程。再次编译错误就会得到解决。

 

在开始前首先解决库的问题-- pthread.h

 

我所下载的版本是

                                              基于vs的RTKLIB2.4.3编译学习历程及经验分享

 

配置步骤为:

a、将\pthreads-w32-2-9-1-release\Pre-built.2\lib\x64下的所有文件(pthreadVC2.lib和libpthreadGC2.a)复制到VS2010安装目录下Microsoft Visual Studio 10.0\VC\Lib中

b、将\pthreads-w32-2-9-1-release\Pre-built.2\include\pthread.h复制到Microsoft Visual Studio 10.0\VC\include下

c、将\pthreads-w32-2-9-1-release\Pre-built.2\dll\x64的所有文件(pthreadGC2.dll和pthreadVC2.dll)复制到Microsoft Visual Studio 10.0\VC\Bin下

 

然后开始创建工程:

1、新建一个空的工程:新建一个visualC++下的空项目

基于vs的RTKLIB2.4.3编译学习历程及经验分享

2、添加文件

a)在工程目录下新建文件夹src,拷贝RTKLIB2.4.3下的src下面的所有文件和rcv文件夹到src下面,同时将app\str2str下面的str2str.c拷贝到src下面,作为主程序入口

b)分别添加头文件和源文件到工程中

3、设置项目属性

选择:项目 > 属性。

设置一:配置属性 >链接器 > 调试 >生成调试信息:是

设置二:配置属性 > C/C++ > 常规 > 调试信息格式:C7

基于vs的RTKLIB2.4.3编译学习历程及经验分享

编译一下,发现一堆问题,下面一一解决。

1、错误77error C1083: 无法打开包括文件:“rtklib.h”: No such file or directoryd

解决思路这是因为没有将rtklib.h头文件的目录包含在项目里的缘故。

将以下路径加入到include目录下(在项目上右键->配置属性->VC++目录->包含目录Include Path选择rtklib.h所在的目录(src)即可)。

2、错误15error C1083: 无法打开包括文件:“sys/time.h”: No such file or directory sys/time.h

解决思路这是linux下面的gcc里面的库函数,不能在VS中使用;RTKLIB中有大量的这样的库,所以我们要设置预处理WIN32

配置属性 > C/C++预处理器 > 预处理定义:WIN32、_CRT_SECURE_NO_DEPRECATE

3、错误1error C2065: “SIGPIPE”: 未声明的标识符

解决思路找到且定义的位置将其注销掉

4、错误1error C2466: 不能分配常量大小为 0 的数组

解决思路在预编译器里面加入 ENAGLO

5、错误31error LNK2019:无法解析的外部符号 [email protected],该符号在函数 _accept_nb 中被引用

解决思路添加附加库[连接器->输入->附加依赖库]添加winmm.lib, ws2_32.lib

6、错误13error LNK2019: 无法解析的外部符号 _showmsg,该符号在函数 _convrnx 中被引用

解决思路一查showmsg这个函数如果在DLL中需要自己定义,rtklib里面已经做好了处理需要在预处理器里面加入DLL即可

最终预处理器定义内包含:
基于vs的RTKLIB2.4.3编译学习历程及经验分享

7、无法将参数 1 从“char [1024]”转换为“LPCWSTR”

选择"项目->属性->配置属性->常规->字符集->未设置",将UNICODE关闭就可以了···

8、无法解析的外部符号 [email protected]

没有加入相应的链接库,添加#pragma comment(lib, "winmm.lib")和#pragma comment(lib, "ws2_32.lib")应该就可以了。

 

 

 

 

完全按照上述步骤,最后出现了如下新的问题:

基于vs的RTKLIB2.4.3编译学习历程及经验分享

不知道是不是rtklib又更新了的缘故,还是什么头文件没有添加???

经思考应该是str2str.c这个文件的问题,因此尝试将此文件移除,并借鉴http://blog.sina.com.cn/s/blog_71d6b76b0102xcg9.html#cmt_5B06A265-79C20602-1854ED4FB-9B2-8C5

这篇文章的说明,将rnx2rtkp.c这个文件添加到项目的源文件中),并将rnx2rtkp.c改名为main.c。(之所以选择这个c文件,是因为rnx2rtkp是rtkpost的CUI版本,主要功能是事后处理,今后调用rtklib中的函数时可以将main函数中原有内容注释掉,另写其他函数。如可简单写个坐标转换的功能,调用了添加进来的c文件中的函数,结果运行成功

 double BLH[3] = {45.0*D2R, 123.0*D2R ,900.0 };

 double XYZ[3] = {0.0, 0.0, 0.0};

 pos2ecef(BLH, XYZ); 

 printf(" X=%f\n Y=%f\n Z=%f\n",XYZ[0],XYZ[1],XYZ[2]);

 getch();

基于vs的RTKLIB2.4.3编译学习历程及经验分享

http://blog.sciencenet.cn/home.php?mod=space&uid=858128&do=blog&id=990823

http://blog.sina.com.cn/s/blog_71d6b76b0102xcg9.html#cmt_5B06A265-79C20602-1854ED4FB-9B2-8C5

这两篇文章大致相同,较为完整的整合了rtklib编译过程中可能会遇到的所有问题,并且所创建项目也是VC++的空项目,可以作为参考进行借鉴。

 

总结与补充。

一般的“变量初始化”等错误,我们都能通过错误列表定位到代码段,进而解决,而添加宏定义、头文件包含路径,容易被开发者忽略。下面总结一下在编译RTKLIB开源库中,所做的添加宏定义、头文件包含路径等操作。

(1)C/C++下预处理器里面我们添加了

(配置属性 ->C/C++ -> 预处理器-> 预处理器定义-> 编辑)

       _CRT_SECURE_NO_WARNINGS

        _WINSOCK_DEPRECATED_NO_WARNINGS

        ENAGLO

        DLL

WIN32

(2)C/C++下的附加包含目录 里面我们添加了

(配置属性 ->C/C++ 常规-> 附加包含目录-> 编辑)

       .\src

(3)连接器下的附加依赖项 里面我们添加了

 (配置属性 -> 链接器 -> 输入 -> 附加依赖项)

        winmm.lib

        ws2_32.lib

 

         通过上面的设置,我们可以发现,我们大多操作的是[C/C++]下的配置选项,而同样,在[VC++]配置选项下,同样有[包含目录],作用几乎与[C/C++]下面的[附加包含目录]一样,我们首先了解【包含目录、库目录、附加包含目录、附加库目录、附加依赖项区别】

VC++目录

    包含目录:寻找#include<xxxx.h>中的xxxx.h的搜索目录

    库目录:寻找.lib文件的搜索目录

C/C++

    常规->附加包含目录:寻找#include<xxxx.h>中的xxxx.h的搜索目录(每一项对应一个文件夹XXXX,文件夹中包含了编译时所需的头文件,使用时直接#include<XXXX>即可)

链接器

    常规->附加库目录:寻找.lib文件的搜索目录

    输入->附加依赖项:lib库(C++的库会把函数、类的声明放在*.h中,实现放在*.cpp或*.c中。编译之后,*.cpp,*.c会被打包成一个.lib文件,这样可以保护源代码)

故,包含目录和附加包含目录(库目录和附加库目录)的区别:

    包含目录:修改了系统的include宏的值,是全局的;

    附加包含目录:用于当前项目,对其他项目没有影响。

    (库目录和附加库目录的区别同上)

进而可知包含目录和附加包含目录(库目录和附加库目录)的区别主要在于全局还是当前,那么当需要对某工程添加这些目录时,通常情况下,都是在附加包含目录和附加库目录中添加的。

补充这些是因为,笔者刚开始编译RTKLIB库时,头文件的包含路径都是添加在[VC++/包含目录]下的,当时惊奇的发现,即使笔者一开始在[VC++/包含目录]下包含的是“绝对路径”,工程也是可以编译通过,并可以移植到任何地方的。但了解到以上以后,建议我们一般使用C/C++和Linker下面的设置,而一般不建议使用VC++下面的设置。