Linux下使用CMAKE和Kdevelop4进行C++开发

Linux下使用CMAKE和Kdevelop4进行C++开发

  • 第一步
  • 第二步
  • 第三步
    • 3.1
    • 3.2
    • 3.3
    • 3.4
    • 3.5
  • 第四步 小结

记录一下这两天参照着《CMake_Practice》在Linux下结合cmake和kdevelop调C++程序的过程
cmake_practice下载链接:https://download.csdn.net/download/hu564823739/12688825
此外不知道怎么回事,kdevelop用不了中文输入法,但是可以显示中文,如果要进行中文注释,使用的方法是,单独打开gedit,把中文注释编辑好之后再复制到由kdevelop打开的cpp或者txt文件中

第一步

1,首先当然是要在Linux上安装cmake和kdevelop啦:

sudo apt-get install cmake
sudo apt-get install kdevelop

第二步

2、再做点准备工作
由于在Linux下路径很重要,所以现在就假设我们已经进入了自己新建的一个叫做class1的文件夹里面了,后面的所有描述都是在这个文件夹下面进行的。由于kdevelop在使用过程中会产生许多的中间过程文件,为了让整个工程看起来不混乱,首先在class1下面首先新建几个惯用的文件夹:
bin:存放最终生成的可执行文件的文件夹
src:存放源文件的文件夹(无论是主函数的源文件还是用于生成库文件的源文件都放在这里面)
include:存放头文件的路径(库文件的头文件和其他的头文件(比如定义类的头文件)都放在这个文件夹下面)
lib:用来存放编译生成的库文件(共享库文件和静态库文件都放在这儿)
大概就是这个样子了:
Linux下使用CMAKE和Kdevelop4进行C++开发_第1张图片
上面的截图是把文件夹从Linux拷贝出来在windows下面截的,所以画风和Linux下面不一样。上图中的 .kdev4文件夹、build文件夹、class1.kdev4 都是kdevelop软件自己生成的,不用管。CMakeLists.txt是等会儿需要自己写的一个文件

第三步

3、Coding time
下面以文件夹为小标题来描述每个文件夹下面有哪些文件以及各个文件中的内容。首先需要介绍cmake的一个大规则:即使CMakeLists.txt文件中什么内容都没有,cmake工程的每一个目录(包括子目录)下面都必须要有一个CMakeLists.txt文件,这是一个硬性的规定,必须要有CMakeLists.txt文件,否则编译的时候要报错

3.1

3.1文件夹class1
class1文件夹下面的CMakeLists.txt文件(使用这个CMakeLists.txt来管理整个工程)新建这个文件之后就可以用kdevelop来打开这个工程了,后面的工作都可以在kdevelop软件中完成了(kdevelop软件是以文件夹来显示整个工程,可以在软件中实现在某个具体的文件夹下添加文件,当然,也可以自己在终端窗口中使用touch或者vim或者gedit手动添加文件到某个具体的文件夹中)。
--------------class1下的CMakeLists.txt里面的内容如下:-------------
#这个是工程目录下的CMakeLists.txt
#注释约定: 符号#后面有@的行说明该内容为必须的项,没有@符号表示该项为可选项

#@设置cmake版本
CMAKE_MINIMUM_REQUIRED(VERSION 2.8)
#@设定工程名
PROJECT(class1)

#设定编译器,这个是可选项
#SET(CMAKE_CXX_COMPILER “g++”)

#打印本工程文件所在的路径,这个是可选项
MESSAGE(STATUS “!!!–project directory: ${PROJECT_SOURCE_DIR}”)

#@添加源文件所在的目录
ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/src)
#向当前工程添加存放源代码文件的目录,其实也可以在此处添加中间二进制或者最终的二进制可执行文件的输出目录,如下:
#ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/src bin)
#如果等会儿我们在工程所在的目录下面新建了一个名叫build的文件夹,然后进入该文件夹,
#然后在该文件夹中输入 cmake . .make 、那么就会在build文件夹中生成一个bin文件夹,
#而在该bin文件夹中就会赫然出现最终生成的可执行文件
#但是此处,已经在src目录下的CMakeLists.txt文件中添加了可执行文件的生成路径,
#即:用SET指令设置了工程的可执行文件输出路径,故此处不再设置

#在需要生成库文件时,使用这个指令指定生成库文件的源文件的存放路径,
#在本例中所有的源文件都放在一个src文件夹下,故只需要使用一次这个指令
#ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/src)
#同理,也可以在该命令后添加一个路径指定最终生成的库文件的存放路径,如下:
#ADD_SUBDIRECTORY(${PROJECT_SOURCE_DIR}/src lib)
#但是在本例中,已经在lib目录下的CMakeLists.txt文件中使用SET(LIBRARY_OUTPUT_PATH …)
#指定了生成的库文件的存放路径

#@设置当前项目模式为调试模式,还可以使用参数 RELEASE设置为发行模式
SET(CMAKE_BUILD_TYPE “DEBUG”)
-----------------------------------分割线------------------------------------------

3.2

3.2文件夹src
这个文件夹下面的文件如下:
class1.cpp 是主函数所在的源文件
class1func.cpp 里面有类方法的定义和两个函数的定义
testfunc.cpp 里面放了一个专门用来测试的函数(打印一句话)
CMakeLists.txt 编译程序所必须的文件
Linux下使用CMAKE和Kdevelop4进行C++开发_第2张图片
------------------------src下的class1.cpp的内容--------------------
#include
#include"class1.h"
#include"testfunc.h"

int main(int argc, char * argu[])
{
using std::cout;
using std::endl;
using std::cin;

Brass person1(“steve”,9527,1000.00);
Brassplus person2(“zhang”,9528,2000.00);

person1.viewaccount();
cout << endl;
person2.viewaccount();
cout << endl;

cout << “Deposite $500 into the zhang`s account.\n” ;
person2.deposit(500);
cout << "Now,the balance of zhang`s account is: "
<< person2.returnbalance() << endl << endl;

cout << “withdrawing $1500 from steve`s account:\n”;
person1.withdraw(1500);
cout << "steve`s account balance:$ "
<< person1.returnbalance() << endl << endl;

cout << “withdrawing $2700 from zhang`s account:\n”;
person2.withdraw(2700);
cout << endl;
person2.viewaccount();

cout << “Please enter a number:”;
int test = 0;
cin >> test;
cout << "This is a number " << test << endl;
cout << “Test successful”;
cout << “This is library test” << endl;
testf();
cout << “---------------------------” << endl;

cin.get();
cin.get();
return 0;
}
-------------------src下的class1func.cpp的内容----------------------
#include"class1.h"
#include

using std::cout;
using std::endl;
using std::string;

typedef std::ios_base::fmtflags format;
typedef std::streamsize precis;
format setformat();
void restore(format f,precis p);
//***************class function:Brass**********************
Brass::Brass(const string & nm,long ac,double ba)
{
fullname = nm;
account = ac;
balance = ba;
}

Brass::Brass()
{
fullname = “Nobody”;
account = -1000;
balance = 0.0;
}

void Brass::deposit(double depmon)
{
if(depmon < 0)
cout << “You can`t deposit negative number of money.\n”;
else
balance += depmon;
}

void Brass::withdraw(double witmon)
{
format initialstate = setformat();
precis initialprec = cout.precision(2);

if(witmon < 0)
cout << “withdrawal amount must be positive,withdrawal cancel.\n”;
else if(witmon <= balance)
balance -= witmon;
else
cout << “withdrawal amount of $:” << witmon
<< " exceeds your balance,withdrawal cancel.\n";
restore(initialstate,initialprec);
}

double Brass::returnbalance() const
{
return balance;
}

void Brass::viewaccount() const
{
format initialstate = setformat();
precis initialprec = cout.precision(2);
cout << “Client name:” << fullname << endl;
cout << “Account number:” << account << endl;
cout << "account balance $: " << balance << endl;
restore(initialstate,initialprec);
}
//--------------------cut-off rule--------------------------------
//**********************class Brassplus function*****************
//function: Brassplus::Brassplus--------
Brassplus::Brassplus(const string & nm,long ac,
double ba,double ml,double rt, double ow)
:Brass(nm,ac,ba)
{
maxloan = ml;
rate = rt;
owes = ow;
}
//function: Brassplus::Brassplus--------
Brassplus::Brassplus(const Brass & somebody,
double ml,double rt,double ow)
:Brass(somebody)
{
maxloan = ml;
rate = rt;
owes = ow;
}
//function: void Brassplus::withdraw--------
void Brassplus::withdraw(double witmon)
{
format initialstate = setformat();
precis initialprec = cout.precision(2);

double bala = returnbalance();
if(witmon <= bala)
Brass::withdraw(witmon);
else if(witmon <= bala + maxloan - owes)
{
double advance = witmon - bala;
owes += advance * (1.00 + rate);
cout << "bank advance : $ " << advance << endl;
cout << "finance charge : $ " << advance * rate << endl;
deposit(advance);
Brass::withdraw(witmon);
}
else
cout << “credit limit execeeded,transaction cancel”;

restore(initialstate,initialprec);
}
//function: void Brassplus::viewaccount--------
void Brassplus::viewaccount() const
{
format initialstate = setformat();
precis initialprec = cout.precision(2);

Brass::viewaccount();
cout << "maximum loan : $ " << maxloan << endl;
cout << “loan rate :” << rate << endl;
cout << "owed to bank : $ " << owes << endl;

restore(initialstate,initialprec);
}

//--------------------cut-off rule--------------------------------
//*****other function

format setformat()
{
return cout.setf(std::ios_base::fixed,std::ios_base::floatfield);
}

void restore(format f,precis p)
{
cout.setf(f,std::ios_base::floatfield);
cout.precision§;
}

---------------------src下的testfunc.cpp的内容---------------------
#include
using std::cout;
using std::endl;

void testf(void)
{
cout << “This is just a test for library” << endl;
}
----------------src下的CMakeLists.txt的内容--------------------------
#这个是src目录下的CMakeLists.txt

#---------------------生成库文件-----------------------------
#@设置生成库文件所使用的源文件的路径
SET(LIBTEST_SRC testfunc.cpp)

#@生成库文件,并且将其命名为test,SHARED参数指定生成共享库,如果改成STATIC则生成静态库
ADD_LIBRARY(testfun SHARED ${LIBTEST_SRC})

#@设定本地编译生成的库文件的输出目录
SET(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/lib)

#--------------------包含本地生成的库文件的路径-----------------
#添加非标准的共享库的搜索路径
LINK_DIRECTORIES(${PROJECT_SOURCE_DIR}/lib)

#---------------------生成可执行二进制文件---------------------
#@设定源代码文件列表
SET(SRC_LIST class1.cpp class1func.cpp)

#@生成可执行文件,命名可执行文件,并指定生成可执行文件使用到的源文件
ADD_EXECUTABLE(class1 ${SRC_LIST})

#@设定工程生成的中间二进制或者最终的二进制可执行文件(即编译的最终输出文件)的输出目录
SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/bin)
#--------------------将目标文件链接到库文件--------------------
#将最终生成的二进制可执行目标文件与其所使用的库文件链接起来
TARGET_LINK_LIBRARIES(class1 testfun)

#------------库文件的头文件以及函数源代码的头文件的路径------------
#@设定头文件的目录,因为在源文件中包含了本地头文件,所以在src的这个CMakeLists.txt文件中必须包含头文件的路径
INCLUDE_DIRECTORIES(BEFORE ${PROJECT_SOURCE_DIR}/include)

3.3

3.3文件夹lib
在这里插入图片描述
上图中的libtestfun.so是生成的共享库,不用管
-----------lib下的CMakeLists.txt的内容-----------------
#这个是lib目录下的CMakeLists.txt
#即使当这个CMakeLists.txt文件中什么都没有,但是必须要有这个文件,否则编译的时候要报错
#这个原则主要是:cmake工程的每一个子目录下面都必须要有一个CMakeLists.txt文件,这是一个硬性的规定

3.4

3.4文件夹include
Linux下使用CMAKE和Kdevelop4进行C++开发_第3张图片
class1.h存放的是类的声明和两个函数的声明
testfunc.h是测试函数的头文件
-----------include下的CMakeLists.txt的内容-----------------
#这个是include目录下的CMakeLists.txt
#虽然这个CMakeLists.txt文件中什么都没有,但是必须要有这个文件,否则编译的时候要报错
#这个原则主要是:cmake工程的每一个子目录下面都必须要有一个CMakeLists.txt文件,这是一个硬性的规定
-----------include下的class1.h的内容-----------------
#ifndef CLASS1_H_
#define CLASS1_H_
#include
class Brass
{
private:
std::string fullname;
long account;
double balance;
public:
//构造函数和默认构造函数于一身4
Brass(const std::string & nm,long ac,double ba);
Brass();
void deposit(double depmon);
virtual void withdraw(double witmon);
double returnbalance() const;
virtual void viewaccount() const;
virtual ~Brass() { };
};
class Brassplus : public Brass
{
private:
double maxloan;
double rate;
double owes;
public:
Brassplus(const std::string & nm = “Nobody”,long ac = -1000,double ba = 0.0,
double ml = 500,double rt = 0.11125, double ow = 0);
Brassplus(const Brass & somebody,double ml = 500,double rt = 0.11125,
double ow = 0);
virtual void withdraw(double witmon);
virtual void viewaccount() const;
void resetmax(double ml) { maxloan = ml; };
void resetrate(double rt) { rate = rt; };
void resetowes() { owes = 0.0; };

};

#endif

-----------include下的testfunc.h的内容-----------------
#ifndef TESTFUNC_H_
#define TESTFUNC_H_

void testf(void);

#endif

3.5

3.5文件夹bin
在这里插入图片描述
calss1文件是最终生成的可执行文件
bin文件夹里面什么都没有,因为只是用这个文件夹来存放生成的可执行文件,它不包含编译、链接过程中会用到的文件,所以也不必写CMakeLists.txt

第四步 小结

4.然后点击kdevelop软件,工具条上的“Build”按钮,就会生成可执行文件和共享库。

总结:在Linux下面调程序比较麻烦一点的就是需要自己来组织程序,从编译到链接都需要自己操心,当然使用IDE(kdevelop、VS code、code::block等等)可以减少一些工作量,但是还是需要自己写CMakeLists.txt。如果出了问题了还是需要自己分析。在Linux下使用IDE调试程序比起用GDB调程序,相对要容易一点。其实cmake相当于是用一种专门的项目管理语言(因为cmake也有自己的语法和指令以及其他的一些参数)。

你可能感兴趣的:(Linux)