mockcpp使用方法详细介绍附难点代码演练

目录

1、Mock介绍

1.1、概述        

1.2、相关概念

1.3、特点

2、对C使用Mock

2.1、安装

2.2、配置

2.3、优缺点

3、Mock规范使用

3.1、sample代码

3.2、核心关键字解析

3.2.1、调用次数约束(expects()/stubs())

3.2.2、调用者选择器(caller)

3.2.3、函数参数约束(with)

3.2.4、调用次序(before、id、after)

3.2.5、函数调用行为(will、then)

3.3、难点代码演练

3.3.1、函数调用行为指定返回值       

3.3.2、入参数约束之内存监控(参数类型也参与检查)

3.3.3、同一个函数指定多个mock规范

3.3.4、入参约束之对象内容监控(spy)

3.3.5、入参约束之定制化检查(check)

3.3.6、指针设置输出参数outBoundP

3.3.7、mock规则匹配失败

3.3.8、mock调用次序(id、before、after)

3.3.9、mock实际调用次数

3.3.10、清空Mock规则GlobalMockObject::verify()


1、Mock介绍

1.1、概述        

        mock工具的作用是指定函数的行为(模拟函数的行为)。可以对入参进行校验,对出参进行设定,还可以指定函数的返回值。例如,当我们在写代码时,涉及到模块间进行交互,双方分别提供了函数接口或消息互相发送时,使用MockCpp进行模拟函数的调用或消息的转发。再如,当我们进行FT测试校验时,涉及到模块间的交互时我们也可以使用MockCpp进行测试用例的补充与校验。

1.2、相关概念

        ①mock规范:每个MOCKER(function)开始,跟一系列的.stubs、.with、.will等的内容的整体,称为一个mock规范。
        ②核心关键字:指stubs/defaults/expects/before/with/after/will/then/id等这些直接跟在‘ . ’ 点后面的关键字。
        ③扩展关键字:指once()/eq()/check()/returnValue()/repeat()等这些作为核心关键字参数的关键字。

1.3、特点

        ① 开源。
        ② mockcpp支持C函数的mock和虚接口的mock。
        ③ VC下,mockcpp支持cdecl和stdcall调用约定的函数。(socket/bind/ftp等函数就是stdcall调用约定的)
        ④ mockcpp的语法清晰、简单,容易理解(参见3.1小节两个sample)。
        ⑤ mockcpp是强类型检查的,强类型检查也是C/C++的一个优势,比如eq(3),如果调用函数时用的参数是UL,那么就应该用eq((UL)3),对于函数返回值也是一样,声明的返回值类型应该跟mock中定义的一致。mock中支持类型检查,可能会发现更多代码BUG的。C++强类型检查,也是为了提高程序安全性,有些问题通过类型检查在编译期可以发现的,就不需要在运行时再痛苦的定位了。C/C++的强类型检查是优势,我们不用把它抛弃了。
        ⑥ mockcpp的错误信息提示非常友好,包含完整的mock规范定义和实际运行情况(参见下面的样例)。

Unexpected invocation: the invocation cannot be found in allowed invoking list.//没有匹配的mock规则
Invoked: add((int)0x1/1, (int)0x2/2)//实际调用add(x,y)传入的参数为1,2
Allowed:
method(add)
  .stubs()
  .invoked(0)//第一次调用
  .with(eq((int)0xa/10), eq((int)0x14/20))//规则指定入参必须为(10,20),所以匹配失败
  .will(returnValue((int)0xc8/200));

2、对C使用Mock

2.1、安装

        需要按照当前我们使用的gtest模式进行编译。在mockcpp/build子目录下执行cmake,其中$xunit_home是gtest头文件所在目录(此时gtest.h路径为$xunit_home/include/gtest/gtest.h)。
        cmake -DMOCKCPP_XUNIT=gtest -DMOCKCPP_XUNIT_HOME=$xunit_home ../
        make
        make install
       安装后的头文件和库在/usr/local下面,可以不用额外指定头文件搜索路径和库文件搜索路径。后续如果觉得好用,也可以把头文件和库提取出来,指定到项目目录树中。

2.2、配置

       测试工程,使用mock接口的文件需要包含:#include <mockcpp/mokc.h>,同时链接mockcpp的库:-lmockcpp

2.3、优缺点

        缺点:被mock的函数,是需要事先存在的,mockcpp并不能完成自动打桩的工作。mockcpp做的,是改变或检查函数的行为,使配合我们的测试工作,虽然mockcpp的实现要复杂得多,但是其用途和原理,和《嵌入式c语言的TDD开发》里的实例是一样的。
        优点:省去打桩的繁琐步骤是mock

3、Mock规范使用

3.1、sample代码

        首先,请看两段mockcpp的使用规范示例代码,其中带“/”或者“|”的表示在该位置可能有多种选择;带中括号的表示是可选的。一段简单的mockcpp使用sample代码:(带有完整核心关键字

TEST(mockcpp simple sample)
{
    MOCKER(function) / MOCK_METHOD(mocker, method)
        .stubs() / defaults() / expects(once())
        [.before("some-mocker-id")]
        [.with(eq(3))]
        [.after("some-mocker-id")]
        .will(returnValue(1)) / .will(repeat(1, 20))
        [.then(returnValue(2))]
        [.id("some-mocker-id")]
}

         下面是一段比较详细的mockcpp使用sample代码:(带有完整扩展关键字)

TEST(mockcpp detail sample)
{
    MOCKER(function) / MOCK_METHOD(mocker, method)
        .stubs() / defaults() / expects(never() | once() | exactly(3) | atLeast(3) | atMost(3) )
        [.before("some-mocker-id")]
        [.with( any() | eq(3) | neq(3) | gt(3) | lt(3) | spy(var_out) | check(check_func)
                | outBound(var_out) | outBoundP(var_out_addr, var_size) | mirror(var_in_addr, var_size)
                | smirror(string) | contains(string) | startWith(string) | endWith(string) )]
        [.after("some-mocker-id")]
        .will( returnValue(1) | repeat(1, 20) | returnObjectList(r1, r2)
                | invoke(func_stub) | ignoreReturnValue()
                | increase(from, to) | increase(from) | throws(exception) | die(3))
        [.then(returnValue(2))]
        [.id("some-mocker-id")]
}

3.2、核心关键字解析

        mockcpp当前的实现支持七种类型的约束/行为:(调用顺序必须按照以下序列进行)
        ① 调用次数约束—— expects()/stubs()
        ② 调用者选择器—— caller()
        ③ 先行调用约束—— before()
        ④ 调用参数约束—— with()
        ⑤ 后行调用约束—— after()
        ⑥ 函数调用行为—— will()/then()
        ⑦ 标识符指定—— id()           

3.2.1、调用次数约束(expects()/stubs())

        紧跟着MOCKER/MOCK_METHOD之后的是stubs、或者defaults、或者expects,三个必须有一个。(这是与AMOCK不同的地方,在这个层次上确定这三个关键字必须有一个,可以让mock语法更清晰)
        ①defaults 表示定义一个默认的mock规范,但它优先级很低;如果后面有stubs或者expects重新指定函数行为,就会按照新指定的来运行。(一般用在setup中)
        ②stubs 表示指定函数的行为,不校验次数。
        ③expects 与stubs的区别就是校验次数。格式:(.expects(once()) / .expects(never()) / .expects(exactly(123)))
            一次:once()
            准确的次数:exactly(n)
            至少:atLeast(n)
                  atLeastOnce()
            至多:atMost(n)
                  atMostOnce()
            不调用:never() 
            注意:次数校验expects()需和GlobalMockObject::verify()一起使用才能校验生效,GlobalMockObject::verify()放在主函 数最后面)

3.2.2、调用者选择器(caller

       这个功能当前主要用于C语言的单元测试/集成测试。当一个函数会被一个流程的多个函数调用时,当其它的选择器很难以进行描述时,可以使用调用者选择器来缩小定位范围。调用者选择器通过caller(function)来指定。其中,function是一个字符串,应该等于调用函数的名字。

3.2.3、函数参数约束(with

    ①入参数约束:
        相等:eq(value)
        不等:neq(value)
        大于: gt(value)
        小于: lt(vlaue)
        内存匹配 :mirror(var_in_addr, var_size)用来约束内存内容的严格相等性。如果用来约束对象内容,则可以忽略size参数
        对象内容监控:spy(address)读取监控对象值
        字符串匹配:smirror(str) 约束字符串的相等性
        startWith(str):入参以str开始
        endWith(str) :入参以str结尾
        占位符: any()
        定制化检查:checkWith(CheckNum(num)) 内部必须是结构体、类
    ② 输出参数约束
        通过引用设置输出参数:outBound(reference, 输入参数约束/sizeof(reference))
        通过指针设置输出参数:outBoundP(pointer, 输入参数约束/sizeof(pointer))    

3.2.4、调用次序(before、id、after)

        ①标识符指定(id):当一个调用描述用到before()/after()等调用顺序约束时,需要给被参照的调用描述一个标识符。标识符通过id(identity)指定。其中identity是一个字符串。在一个对象范围内,identity必须唯一,否则mock++则可能会引用到错误的调用描述。
        ②before(id):之前
        ③after(id):之后
        注意:(before、id、after不能和stubs一起使用)

3.2.5、函数调用行为(will、then)

        ①will指定返回值/②then指定下一次返回值
        返回一个值:returnValue(value)
        重复返回一个值:repeat(value, times)
        步增一个值:increase(from, to)/increase(from)
        返回一系列的值:returnObjectList(o1, o2,…);依次返回o1, o2,…;超过返回列表数据个数,报错。返回个数有限。
        抛出异常:throws(exception(“Exception!”))
        异常退出:die表示程序退出,并且返回指定的值。用于模拟一个函数调用崩溃的情况。
        忽略返回值:ignoreReturnValue(),如果函数定义的返回值类型不是void ,则一定要指定函数调用行为;即使不关心返回值,也要通过ignoreReturnValue()来指定。
        转调一个stubFunction函数:invoke(stubFunction)
        注意:带有返回值的函数,MOCKER后面必须有will,否则mockcpp认为无返回值,校验时会发现返回类型不匹配。

接口:char * sysMemRosBottom (void){}
mock规则:MOCKER(sysMemRosBottom).expects(once()).will(returnValue(NULL));

错误:
.../mockcpp/ChainableMockMethod.h:69: Failure
Returned type does NOT match the method declaration
Required : char*
Returned : long, which is from
method(sysMemRosBottom)
     .expects(once())
     .invoked(1)
     .will(returnValue((long)0/0));
unknown file: Failure
C++ exception with description "failed due to mockcpp exception" thrown in the test body.

3.3、难点代码演练

3.3.1、函数调用行为指定返回值       

       will指定函数的返回值:.will(returnValue(expect_var));如果要多次重复的相同值,则用.will(repeat(expect_var, repeat_cnt)),若果超过返回次数,后面没有接then,则报错需要指定下一次返回值则用.then(returnValue(expect_var));具体见如下代码

    int i=0,repeat_cnt = 20,expect_var = 100;
    //入参1,2:前repeat_cnt次,返回值为expect_var;第repeat_cnt+1次,返回值expect_var+1
    MOCKER(add).defaults().with(eq(1), eq(2)).will(repeat(expect_var, repeat_cnt)).then(returnValue(expect_var+1));
    //入参3,4:第一次返回值为expect_var;第2,3,4....次,返回值expect_var+1
    MOCKER(add).defaults().with(eq(3), eq(4)).will(returnValue(expect_var)).then(returnValue(expect_var+1));


    for(i = 0; i < repeat_cnt; i++)
    {
      EXPECT_EQ(expect_var, add(1,2));  
    }
    EXPECT_EQ(expect_var + 1, add(1,2));
    
    EXPECT_EQ(expect_var, add(3,4));
    EXPECT_EQ(expect_var+1, add(3,4));//之后的返回值均为expect_var+1
    EXPECT_EQ(expect_var+1, add(3,4));//第3次
    GlobalMockObject::verify();

3.3.2、入参数约束之内存监控(参数类型也参与检查)

       当函数的入参为一个指针时,此时eq(var)则无法校验指针指向的地址的内容,改用mirror(var_in_addr, var_size),用于监控内存地址中的内容,类似C标准库中的int memcmp(const void *s1, const void *s2, size_t n),参数类型必须一致(显示强转),否则匹配失败,;具体代码如下 :

int testMethodInParaPointer(char* str)
{
    return 0;
}

int callTestMethodInParaPointer()
{

    char temp[10]={"hello"};
    return testMethodInParaPointer(temp);
}

TEST(RosMemBuf_adjust_capacity_T, GIVEN_ANY_WHEN_CALL_testMethodInParaPointer_THEN_OK)
{
 
    int expect_var = 100;
    /*eq(var),全局变量和局部变量不同无法匹配,显示:the invocation cannot be found in allowed invoking list*/
    //MOCKER(testMethodInParaPointer).defaults().with(eq((char*)"hello")).will(returnValue(expect_var));
    /*字符串"hello"需要加(char *),否则解析成(char const *)依然无法匹配*/
    MOCKER(testMethodInParaPointer).defaults().with(mirror((char *)"hello",strlen("hello"))).will(returnValue(expect_var));
    EXPECT_EQ(expect_var,callTestMethodInParaPointer());
    GlobalMockObject::verify();    
}

3.3.3、同一个函数指定多个mock规范

       当对同一个函数指定多个mock规范,那么这些mock规范一般是应该在输入方面有差异的,否则没必要指定多个。而且,在输入方面无差异的两个mock规范,让mockcpp内部无法判断是否满足规范约束。 比如,测试函数 void testMtehodParaInOut(int input,int *p_output),前面一个是入参,后面一个是出参,希望input为10时,输出*p_output为100,input为11时,输出*p_output为111,那么应该这样写:

    int in_var = 10,expect_var = 100,real_var1 = 0;
    
    MOCKER(testMtehodParaInOut).expects(once()).with(eq(in_var),outBoundP(&expect_var,sizeof(expect_var))); 
    testMtehodParaInOut(in_var,&real_var1);
    EXPECT_EQ(expect_var, real_var1);

    expect_var = 111;
    MOCKER(testMtehodParaInOut).expects(once()).with(eq(in_var+1),outBoundP(&expect_var,sizeof(expect_var))); 
    testMtehodParaInOut(in_var+1,&real_var1);
    EXPECT_EQ(expect_var, real_var1);

    GlobalMockObject::verify();

        假设你把eq(in_var)、eq(in_var+1)写为any(),那么mockcpp会判断你的两个调用testMtehodParaInOut(in_var,&real_var1);和testMtehodParaInOut(in_var,&real_var1);都符合第一个mock规范,从而报告与你定义的次数1不匹配。或者仅有一条mock规范(此时outBoundP相同),但是实际调用两次保同样的错,信息如下:

.../ChainableMockMethod.h:69: Failure
Invocation is expected only once(), but you are trying to invoke more than that
method(testMtehodParaInOut)
     .expects(once())
     .invoked(1)//实际调用次数
     .with(any(), outBoundP((int*)0x00ada680));
unknown file: Failure
C++ exception with description "failed due to mockcpp exception" thrown in the test body.

3.3.4、入参约束之对象内容监控(spy)

    spy的作用是监视,下面例子,就是监视test在调用add时,传入的值是多少。有些时候,测试用例需要这样的值,这种方式是很有效的。

    int var_out1, var_out2,expect_var = 100;
    MOCKER(add).defaults().with(spy(var_out1),spy(var_out2)).will(returnValue(expect_var));
    EXPECT_EQ(expect_var, add(3,4));
    EXPECT_EQ(var_out1, 3);//监控到第一个参数为3
    EXPECT_EQ(var_out2, 4);//监控到第二个参数为4

3.3.5、入参约束之定制化检查(check)

      约束关键字中,有很多都是对入参进行检查的,比如eq、neq、lt、gt等等,但它们都只实现了非常简单的检查。 如果用户想做一个定制化的检查,那么就可以用check,但是编译报错 error: 'check' was not declared in this scope,原因:mockcpp在2.4版本后没有了check关键字,代替的是checkWith注意大小写,以为还有一个CheckWith。 举一个例子:假设用户想检查入参p指向的结构的字段b是否大于10,那么可以如下这样写:


typedef struct data_in{
    int a;
    int b;
}def_data_in;

//定义在C++中,不要定义在C中,编译无法识别bool(小写),
bool checkTestMockcppCheckEx1(def_data_in *pdata){
    if(pdata->a >10)
        return true;
    else
        return false;
}
//实现一个检查函数,入参类型跟要检查的入参相同,返回值为bool,返回true表示检查通过。
bool checkTestMockcppCheckEx2(def_data_in *pdata){
    if(pdata->b == 10)
        return true;
    else
        return false;
}

int testMockcppCheck(def_data_in *pdata1, def_data_in *pdata2 ){

    return 0;
}

TEST(xxxxx, DoubleParaTest)
{
    def_data_in g_data1={11,9},g_data2={11,10};
    int expect_var = 100;
    MOCKER(testMockcppCheck).stubs()
    .with(checkWith(checkTestMockcppCheckEx1),checkWith(checkTestMockcppCheckEx2))//将校验参数填写到原来的参数限定位置
    .will(returnValue(expect_var));

    EXPECT_EQ(expect_var, testMockcppCheck(&g_data1,&g_data2));   
}


int func(int in, def_data_in *p)
{
    return 0;//mockcpp对类型进行检查,对于有返回值类型的接口,没有return操作,打桩后会出现Segmentation fault
}

TEST(xxx, SingleParaTest)
{
    def_data_in var={1,10};
    int expect_var = 100;
    MOCKER(func)
        .stubs()
        .with(any(),checkWith(checkTestMockcppCheckEx2))// error: 'check' was not declared in this scope,mockcpp在2.4版本后没有了check关键字,注意大小写,以为还有一个CheckWith
        .will(returnValue(expect_var));
    EXPECT_EQ(expect_var, func(1, &var));
}

3.3.6、指针设置输出参数outBoundP

         实际打桩过程中,经常需要指定接口出参的数值,当出参的类型为指针时则需要设置指针指向地址的内容,此时需要通过outBoundP来指定,具体代码如下:

void testMtehodParaInOut(int input,int *p_output)
{
    *p_output = input +1;
}
...
int in_var = 10,expect_var = 12,real_var1 = 0; 
MOCKER(testMtehodParaInOut).stubs().with(eq(in_var),outBoundP(&expect_var,sizeof(expect_var))); //指定出参的指针内容为12
testMtehodParaInOut(in_var,&real_var1);//调用后,real_var1的指针内容为12
EXPECT_EQ(expect_var, real_var1);

3.3.7、mock规则匹配失败

        如果要对某个函数(比如add)指定多个调用不同的行为(多个mock规范),比如调用入参为1,2时,返回30;调用入参为3、4时,返回300。那么可以这样写:

    MOCKER(add).stubs().with(eq(1), eq(2)).will(returnValue(30));
    MOCKER(add).stubs().with(eq(3), eq(4)).will(returnValue(300));
    EXPECT_EQ(300, add(1,4));//没有匹配的mock规则,运行报错
    GlobalMockObject::verify();

只有参数满足条件桩函数才会生效,如果调用接口(add)没有匹配到mock规则,则报错(意外调用:在允许的调用列表中找不到调用),具体如下:

....../mockcpp/ChainableMockMethod.h:69: Failure

=====================================
Unexpected invocation: the invocation cannot be found in allowed invoking list.
Invoked: add((int)0x1/1, (int)0x4/4)
Allowed:
method(add)
     .stubs()
     .invoked(0)
     .with(eq((int)0x1/1), eq((int)0x2/2))
     .will(returnValue((int)0x1e/30));

method(add)
     .stubs()
     .invoked(0)
     .with(eq((int)0x3/3), eq((int)0x4/4))
     .will(returnValue((int)0x12c/300));

=====================================

unknown file: Failure
C++ exception with description "failed due to mockcpp exception" thrown in the test body.

结论:只要打桩了,那么就不会运行原函数,都是与mock规范匹配,运行桩,否则运行报错

3.3.8、mock调用次序(id、before、after)

如果上面的3.3.7小结的例子,希望对调用顺序做严格要求,必须第一次调用参数是1、2,第二次是3、4,那么可以这样写:

MOCKER(add)
  .stubs()
  .with(eq(1), eq(2))
  .will(returnValue(30))
  .id("first");

MOCKER(add)
  .stubs()
  .with(eq(3), eq(4))
  .after("first")
  .will(returnValue(700));

        自定义规则:假设有时候需要对同一个函数指定多个mock规范,并且它们是有规律的,那么可以借助循环来简化代码。 假设要mock的函数是void function(int in),希望它依次以0、1、2...10为入参被调用,每次都调用一次,那么可以像这样写:

MOCKER(function)
  .expects(once())
  .with(eq(0))
  .id("0");

for (int i = 1; i <= 10; i++)
{
  MOCKER(function)
    .expects(once())
    .with(eq(i))
    .after(string(i - 1))
    .id(string(i));   
}

//没有实验,编译失败,版本(2.6)无法编译mock规则的id、after、before等着字段,显示:error: 'struct mockcpp::StubBuilder<mockcpp::MoreStubBuilder<mockcpp::DummyBuilder> >' has no member named 'after'。查阅对应的ChainingMockHelper.h,发现确实没有实现。需要更新版本

3.3.9、mock实际调用次数

        在实际打桩过程我们可以通过expects(exactly(x))指定其精确运行x次,超过则报错,代码如下

    MOCKER(add).expects(exactly(2)).with(eq(100), eq(200)).will(returnValue(30));
    EXPECT_EQ(30, add(100,200));
    EXPECT_EQ(30, add(100,200));
    EXPECT_EQ(30, add(100,200));
    GlobalMockObject::verify();

提示错误信息:

.../ChainableMockObjectBase.cpp:85: Failure
Expected invoking exactly 2 times, but it's actually invoked 3 times.
method(add)
     .expects(exactly(2))
     .invoked(3)//实际第3次调用
     .with(eq((int)0x64/100), eq((int)0xc8/200))
     .will(returnValue((int)0x1e/30));
unknown file: Failure
C++ exception with description "failed due to mockcpp exception" thrown in the test body.

3.3.10、清空Mock规则GlobalMockObject::verify()

        使用mockcpp时,校验是否按照mock规范进行调用的,应该用:GlobalMockObject::verify();verify之后,会自动执行reset。通常在进行Unit测试时,需要避免用例之间的联系,不能上一个用例的桩函数在本例生效,需要在用例的结尾处执行该语句。

### 回答1: 以下是Ubuntu 18.04安装NVIDIA显卡驱动的教程: 1. 打开终端,输入以下命令以添加NVIDIA PPA存储库: sudo add-apt-repository ppa:graphics-drivers/ppa 2. 更新软件包列表: sudo apt-get update 3. 安装NVIDIA显卡驱动: sudo apt-get install nvidia-driver-440 (请注意,这里的“440”是指驱动程序的版本号,您可以根据您的显卡型号和要求选择不同的版本号) 4. 安装完成后,重新启动计算机: sudo reboot 5. 检查驱动程序是否正确安装: nvidia-smi 如果您看到了NVIDIA显卡的详细信息,则表示驱动程序已正确安装。 希望这个教程能够帮助您成功安装NVIDIA显卡驱动程序。 ### 回答2: Ubuntu 18.04是一款非常流行的Linux发行版,但是在安装nvidia显卡驱动时可能会遇到一些困难。接下来,我将为大家介绍ubuntu18.04安装nvidia显卡驱动的详细步骤。 第一步:检查系统是否自带nvidia驱动。 在安装nvidia显卡驱动之前,我们需要检查系统是否已经自带了它。可以使用以下命令来检查: ``` lsmod | grep nvidia ``` 如果系统中已经有nvidia驱动,则会显示以下信息: ``` nvidia_uvm 985673 0 nvidia_drm 45056 8 nvidia_modeset 1114112 15 nvidia_drm nvidia 20257792 431 nvidia_uvm,nvidia_modeset drm_kms_helper 172032 2 nvidia_drm,i915 drm 401408 13 drm_kms_helper,nvidia_drm,i915 ``` 如果没有输出,说明系统中没有自带的nvidia驱动。 第二步:下载nvidia显卡驱动。 我们需要从nvidia官网下载适用于我们显卡的驱动。可以使用以下命令查看本机的显卡信息: ``` lspci -vnn | grep VGA -A 12 ``` 然后根据显卡型号在nvidia官网下载对应的驱动,比如说我们的显卡型号是GTX 1060,则可以到以下网址下载: ``` https://www.nvidia.com/Download/index.aspx?lang=en-us ``` 第三步:安装nvidia显卡驱动。 1. 在安装nvidia驱动之前,我们需要先停止GUI界面,可以使用以下命令来停止: ``` sudo systemctl stop gdm ``` 2. 将下载的驱动复制到/home目录下,然后打开终端,使用以下命令将当前目录更改为/home目录: ``` cd ~ ``` 3. 使用以下命令将驱动文件修改为可执行文件: ``` chmod +x NVIDIA-Linux-x86_64-XXX.XX.run ``` 4. 运行以下命令安装驱动: ``` sudo ./NVIDIA-Linux-x86_64-XXX.XX.run ``` 注意:在安装驱动期间,将会提示你是否安装nvidia的DKMS驱动,这意味着如果更新内核则会自动重新编译模块。建议选择“是”。 5. 安装完成后,使用以下命令重启GUI界面: ``` sudo systemctl start gdm ``` 到此,ubuntu18.04安装nvidia显卡驱动的教程就介绍完了。希望对大家有所帮助。 ### 回答3: Ubuntu 18.04是一个广受欢迎的免费和开源的操作系统,可用于个人和企业计算机。对于拥有NVIDIA显卡的用户,安装正确的显卡驱动程序是非常重要的,这有助于显卡的稳定性和性能。以下是Ubuntu 18.04安装NVIDIA显卡驱动程序的教程。 第1步:检查NVIDIA驱动适用于您的显卡 在安装驱动程序之前,您需要确定正确的驱动程序版本适用于您的NVIDIA显卡。您可以在NVIDIA官方网站上找到相应的驱动程序。请注意,您需要知道您的显卡型号和操作系统位数(即32位或64位)。 第2步:更新Ubuntu 18.04 在安装NVIDIA显卡驱动程序之前,我们建议您先更新Ubuntu 18.04。这可以通过在终端中输入以下命令来完成: sudo apt update sudo apt upgrade 第3步:安装NVIDIA显卡驱动程序 要安装NVIDIA显卡驱动程序,请按照以下步骤操作: 1.打开“Software & Updates”(软件和更新)应用程序。 2.单击“Additional Drivers”(其他驱动程序)选项卡。 3.在这里,您将看到一个列表,其中包含可用的NVIDIA驱动程序版本。选择您想要的驱动程序版本并单击“Apply Changes”(应用更改)按钮。 4.驱动程序开始下载和安装。这可能需要一些时间。完成后,您需要重新启动计算机以使更改生效。 完成这些步骤后,您应该成功安装了NVIDIA显卡驱动程序。您可以通过在终端中输入以下命令来检查当前正在运行的驱动程序版本: nvidia-smi 希望这个教程对于想要在Ubuntu 18.04中安装NVIDIA显卡驱动程序的用户有所帮助。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

老王不让用

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值