libgit2使用教程(一)实现 git init

主要内容:
1. 使用 libgit2 的准备工作
2. 构建和运行
3. 初始化一个 git 仓库

示例代码:https://github.com/XiaochenFTX/libgit2_samples

进入正题

开始直接到 libgit2 的 readme 我们首先需要从那里获取一些有用的信息。
官网:https://libgit2.github.com/
API:http://libgit2.github.com/libgit2/
虽然官方文档写的挺水的,不过毕竟可以获得信息的途径就这么少,所以凑合着也还能用。

接下来提到了两个非常重要的函数, init 和 shutdown ,必须保证在任何操作之前调用初始化:

git_libgit2_init();

释放 init 申请的资源,使用:

git_libgit2_shutdown();

这样就可以开始第一个程序了

#include <git2.h> 

int main() 
{ 
    git_libgit2_init(); 
    
    git_libgit2_shutdown();

     return 0; 
}

ok 打完收工。

先把它跑一下看看,如果可以正常跑完,就说明所有的构建基本上都没啥问题了。

当然,这并没有什么卵用。接下来来搞个有意义的代码来结束这篇。
第一个例子就实现一下 git init

const char* path = "/Users/XiaochenFTX/Documents/data";
git_repository *rep = nullptr;
git_repository_init(&rep, path, 0);

打完收工。

当然,良好的编程习惯,在最后不要忘了释放资源。

git_repository_free(rep); 
git_libgit2_shutdown();

接口的详细说明可以去查官方的 API 我会在必要的地方对一些我觉得比较重要的东西进行说明。

git_repository_init 的第一个参数是将初始化好的 git_repository 指针返回,这个库的接口基本上都是这个风格的,以后就不再提这个事了。
这个函数会返回一个错误码,返回值为 0 表示执行成功,小于 0 表示有错误。所以可以通过判断返回值得方式来确定函数调用是否成功。
想知道具体报错信息,可以调用 giterr_last() 这个函数返回一个 git_error 结构体指针。

/**
* Structure to store extra details of the last error that occurred.
*
* This is kept on a per-thread basis if GIT_THREADS was defined when the
* library was build, otherwise one is kept globally for the library
*/
typedef struct {
    char *message;
    int klass;
} git_error;

klass 对应 git_error_t 的枚举值,用于说明是哪部分出的问题。message 是一个人类可以看懂的的说明信息。开发中遇到问题可以把这个信息打印出来,对找问题有很大帮助。

最终完成 sample1 的代码就是这个样子

#include <git2.h>
#include <iostream>

int main()
{
    git_libgit2_init();
    const char *path = "/Users/XiaochenFTX/Documents/data";
    git_repository *rep = nullptr;
    
    // git init
    int error = git_repository_init(&rep, path, 0);
    if (error < 0) {
        const git_error *e = giterr_last();
        std::cout << "Error: " << error << " / " << e->klass << " : " << e->message << std::endl;
        
        goto SHUTDOWN;
    }
SHUTDOWN:
    git_repository_free(rep);
    git_libgit2_shutdown();
    
    return 0;
}

最后解释一下为什么要用 goto
很多同学在学习 C 语言的时候,如果遇到不负责任的老师,都会强调不要用 goto 这个东西,更有甚者干脆讲都不讲。而具体原因不外乎:会让代码逻辑混乱,可读性差,不好调试
当然,造成这些后果,都是在“如果用不好”的前提下的。然而,我认为这个语言特性真的不是不值一提的垃圾,把 goto 用好在一定程度上是可以让代码更美观、更简洁、更易读。
随便举个例子,比如跳出多层循环,难道还要引入一个外层变量再逐层判断吗?在这种情况下那种方式可读性更高?
还有就是在错误发生的情况下,直接跳到函数结尾进行清理。如果不使用 goto ,我见过几种奇葩方案,最突出的应该是用 do{}while(0); 吧,这样强行为了不用 goto 而产生的奇葩行为,我只能呵呵了。
所以,我推荐在必要的时候使用 goto 来使代码更清晰、简洁。当然,也不是随便瞎用,任何工具都有其最佳适用范围,不能矫枉过正。

附一、代码中引用 libgit2:
在根目录的 CMakeLists.txt 中把相关工程文件夹都用 add_subdirectory 加进来,并且指定 libgit2 的 include 为引用目录

include_directories(extras/libgit2/include)
add_subdirectory(extras/libgit2)
add_subdirectory(sample1)

在需要链接这个库的工程中使用 target_link_libraries 链接上 libgit2
就像我们的 sample1 中这样

target_link_libraries(sample1 git2)

有些环境下会报找不到 -lssh2 的错误:
ld: library not found for -lssh2
只要在根目录的 CMakeLists.txt 中加上一句:

LINK_DIRECTORIES(${LIBSSH2_LIBRARY_DIRS})

这样简单的构建系统就搭建好了,可以开始写代码了
使用其他 IDE 的话,直接用 cmake 导出对应的工程,在自己创建的工程中引入就可以了。
不太推荐直接编译好库放到工程里使用,我自己试了之后发现它用到的几个第三方库还需要自己手动构建再引用。

附二、示例代码的使用:

1. 从 github 上拉代码

git clone git@github.com:XiaochenFTX/libgit2_samples.git
cd libgit2_samples
git submodule update –init –recursive

2. 使用 cmake 导出熟悉的 IDE 工程,或者直接构建运行

mkdir build 
cd build/

Xcode:

cmake .. -G “Xcode”

Visual Studio:

cmake .. -G "Visual Studio"

直接构建:

cmake .. 
make

我使用的 IDE 是 Clion ,使用 Clion 导入工程也可以直接使用

MacOS OpenGL窗口程序的正确打开方式

当小白挖开gl渲染这个坑的时候,最先遇到的问题一定是窗口。然后就是虐死强迫症系列的剧情。
教程最多的一定是glut系列,然而,放到Xcode里一片黄,原因是苹果在未来要不支持这玩意了。再之后就是glew、glfw等一堆库,到这个时候一个没什么基础的小白玩家应该已经有流失的想法了。
这篇博客主要介绍怎么直接搞出一个干净的glview窗口程序,简简单单的开始OpenGL的新手引导。

然后也可以解决一些问题:
1. 如何创建一个OpenGL窗口
2. glut的警告问题
3. 可以使用4.0以上版本的OpenGL
4. 对于非小白玩家而言可能第3条是最重要的

废话少说,书归正传:
第一步、创建工程
1. 新建一个Cocoa Application工程
130298
2. 拖一个OpenGL View 替换掉原来的默认View
582077
这样这个窗口就可以启动运行了。

第二步、写代码
1. 新建一个Cocoa Class,选择继承自 NSOpenGLView
306506
2. 把上边建好的GLView关联上我们自己的类
742882
这样就可以在我们自己类中调用渲染代码了。

第三步、支持GL4.1
需要实现的函数:
initWithCoder
defaultPixelFormat
prepareOpenGL
drawRect

重点就是在初始化部分,需要设置一下属性才能真正的支持4.1

- (nullable instancetype)initWithCoder:(NSCoder *)coder { 

   [[self openGLContext] makeCurrentContext]; 

   self = [super initWithCoder:coder]; 

   return self; 
} 

+ (NSOpenGLPixelFormat*)defaultPixelFormat { 
   NSOpenGLPixelFormatAttribute attrs[] = 
   { 
      NSOpenGLPFADoubleBuffer, // 可选地,可以使用双缓冲 
      NSOpenGLPFAOpenGLProfile, // Must specify the 3.2 Core Profile to use OpenGL 3.2 
      NSOpenGLProfileVersion4_1Core, 
      0 
   }; 

   return [[NSOpenGLPixelFormat alloc] initWithAttributes:attrs]; 
}

这样就是一个可以正常撸的GL窗口程序了。非常适合强迫症玩家入门使用,编译器完全没有警告。

在这就不贴完整代码了。有一个可运行的程序,在github上。
https://github.com/XiaochenFTX/glFirst

curl在Android系统卡死的问题

问题描述:
调用 curl 获取消息头的时候,发现程序卡住不动了。代码如下:

curl_easy_setopt(curl, CURLOPT_URL, srcUrl.c_str());
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
curl_easy_perform(curl); // 这句直接卡死,没有任何返回

经测试发现,不做任何设置,做一次发送,同样会卡死。

curl_easy_setopt(curl, CURLOPT_URL, srcUrl.c_str()); 
curl_easy_perform(curl); // 这句直接卡死,没有任何返回

解决方案:

经过反复试验,在请求的时候设置写数据回调,就可以正常执行了。

void size_t writeFunc(void *ptr, size_t size, size_t nmemb, void *userdata)
{
    return 0;
}
curl_easy_setopt(curl, CURLOPT_URL, srcUrl.c_str());
curl_easy_setopt(curl, CURLOPT_HEADER, 1);
curl_easy_setopt(curl, CURLOPT_NOBODY, 1);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writeFunc);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, nullptr);
curl_easy_perform(curl);

具体原因不详,暂时没有精力去读它的代码。我猜卡死的问题与代码本身关系不大,暂时比较怀疑编译库的工具链。由于之前遇到过 ndk 编译出的 sscanf 等函数调用卡死,所以这货暂时列为A级怀疑对象。

C++ 如何让自己的类支持foreach

首先,我们先看看使用 foreach 的时候,都发生了什么。

新建一个类,根据经验,我们 for 一个对象应该是这样的:
for (XX::iterator iter = xx.begin(); iter != xx.end(); ++iter)
所以,迭代器, beigin(), end() 应该是会用得到的,我们做个试验:
Generator.h
class Generator 
{
public:
    typedef int *iterator;
    iterator begin();
    iterator end();
};

Generator.cpp

Generator::iterator Generator::begin()
{
    std::cout << "begin()" << std::endl;
    return nullptr;
}

Generator::iterator Generator::end()
{
    std::cout << "end()" << std::endl;
    return nullptr;
}
main.cpp
Generator g;
for (auto i: g)
{
    std::cout << i << std::endl;
}
运行结果:
begin() 
end()
说明我们想的没错,foreach 跟上边的 for 的行为是一样的。
插个体外话,(发现字打错了,不过不改了,还是挺哏儿的)
1. 之前以为 for (const auto i : g) 会调用 const 版本的 cbegin cend ,然而 并不会。
2. iterator 叫什么名字都没什么所谓,起名叫 红太阳 也ok。
接下来,处理一下迭代器:(我想确认一下丫具体被如何操 做)
class iterator
{
public:
    iterator(int*p)
    : _p(p)
    {
    }
    int * operator()()
    {
        std::cout << "operator()" << std::endl;
        return _p;
    }
    int operator*()
    {
        std::cout << "openator*" << std::endl;
        return 0;
    }
    iterator & operator++()
    {
        std::cout << "++operator" << std::endl;
        ++_p;
        return *this;
    }
    iterator operator++(int)
    {
        std::cout << "operator++" << std::endl;
        return _p++;
    }
    bool operator==(const iterator& it)
    {
        std::cout<< "operator==" <<std::endl;
        return true;
    }
    bool operator!= (const iterator& it)
    {
        std::cout<< "operator!=" <<std::endl;
        return true;
    }
private:
    int *_p;
};
输出结果:
begin() 
end() 
operator!= 
openator* 
0 
++operator 
operator!= 
openator* 
0 
++operator 
operator!= 
openator* 
0

已经足够说明问题了,自己把剩下的细节补充上就好了。

总结一下要点:
1. begin() end()
2. 迭代器
3. 迭代器重载 !=
4. 迭代器重载 前++
5. 迭代器重载 *(解引用)

iOS命令行打包的坑

最近在搞自动打包的时候,不小心踩到了了烂水果没有来得及擦干净的菊花。

总结一下经验教训:
1.技术
找不到ResourceRules.plist
类似这样的警告:
Warning: –resource-rules has been deprecated in Mac OS X >= 10.10! /tmp/QYFSJIvu7W/Payload/XX.app/ResourceRules.plist: cannot read resources
经过我缜密的调(gu)查(ge)取(bai)证(du),大致上可以猜测是烂水果更新了签名机制后并没有更新整套命令行工具。
秘密就藏在……
执行以下命令:
xcrun -sdk iphoneos -f PackageApplication

定位到 PackageApplication 然后用随便什么文本编辑器打开

搜索 ResourceRules ,定位到之后,清理掉与她有关的参数,整成这样:
my @codesign_args = ("/usr/bin/codesign", "--force", "--preserve-metadata=identifier,entitlements", "--sign", $opt{sign});

就这样。

亲测有效,目前尚未发现副作用。
参考文献:(临时找来凑数的)
2.
签名验证失败:
Program /usr/bin/codesign returned 1 :
resource envelope is obsolete 这个错误
stackoverflow 上大神给出的解决方案就是在 codesign 验证的时候,加上 –no-strict (不严格验证?这尼玛确实不报错了,然而……总之就是不报错了)
具体操作方式,也是向上边一样,修改 PackageApplication
找到 —verify 那行 加上 –no-strict 参数:
my $result = runCmd("/usr/bin/codesign", "--verify", "--no-strict", "-vvvv", $plugin );

参考资料:

RSS
Follow by Email
YouTube
YouTube
Pinterest
fb-share-icon
LinkedIn
Share
VK
Weibo
WeChat
WhatsApp
Reddit
FbMessenger
Copy link
URL has been copied successfully!