微软什么的最讨厌啦~写个 GUI 程序要么带个控制台窗口,要么就得用非主流的 WinMain 函数作入口。

用 gcc 的话,这其实不是个问题,带上一个 -mwindows 参数即可顺利解决掉控制台窗口并且抛弃 WinMain。

而到了 Visual Studio,似乎很两难:

Linker 参数中 SubSystem 选择 Windows 可以去除控制台窗口,但会要求用 WinMain 作入口。
Linker 参数中 SubSystem 选择 Console 可以使用 main 作入口,但会自带控制台窗口。
于是困惑了。好在今天在 Irrlicht 的教程中见到了解法:

Linker 参数中的 SubSystem 继续选择 Windows,与此同时将 Entry Point 设置为 mainCRTStartup 即可兼得鱼和熊掌。

以命令行参数形式就是:/SUBSYSTEM:windows /ENTRY:mainCRTStartup

要点就是 ENTRY 参数有三种:mainCRTStartup、WinMainCRTStartup、和 _DllMainCRTStartup,分别对应调用 main、WinMain、和 DllMain,默认是根据 /DLL 和 /SUBSYSTEM 参数自动选择的。

#ifdef _DEBUG
    #ifdef UNICODE
        #pragma comment(linker, "/subsystem:\"console\" /entry:\"wWinMainCRTStartup\"")
    #else
        #pragma comment(linker, "/subsystem:\"console\" /entry:\"WinMainCRTStartup\"")
    #endif
#endif

#include <codecvt>
#include <locale>

namespace std
{
    class codecvt_chs : public std::codecvt_byname<wchar_t, char, std::mbstate_t>
    {
    public:
        explicit codecvt_chs() : codecvt_byname("chs") 
    };
}

static bool U2W(const std::string& source, std::wstring& buffer)
{
    try
    {
        buffer.swap(*const_cast<std::wstring*>(std::addressof(static_cast<const std::wstring&>(std::wstring(std::wstring_convert<std::codecvt_utf8<wchar_t>>().from_bytes(source))))));
        return true;
    }
    catch (const std::range_error& ex)
    {
        printf("%s", ex.what());
    }

    return false;
}

static bool W2U(const std::wstring& source, std::string& buffer)
{
    try
    {
        buffer.swap(*const_cast<std::string*>(std::addressof(static_cast<const std::string&>(std::string(std::wstring_convert<std::codecvt_utf8<wchar_t>>().to_bytes(source))))));
        return true;
    }
    catch (const std::range_error& ex)
    {
        printf("%s", ex.what());
    }

    return false;
}

static bool A2W(const std::string& source, std::wstring& buffer)
{
    try
    {
        buffer.swap(*const_cast<std::wstring*>(std::addressof(static_cast<const std::wstring&>(std::wstring(std::wstring_convert<std::codecvt_chs>().from_bytes(source))))));
        return true;
    }
    catch (const std::range_error& ex)
    {
        printf("%s", ex.what());
    }
    return false;
}

static bool W2A(const std::wstring& source, std::string& buffer)
{
    try
    {
        buffer.swap(*const_cast<std::string*>(std::addressof(static_cast<const std::string&>(std::string(std::wstring_convert<std::codecvt_chs>().to_bytes(source))))));
        return true;
    }
    catch (const std::range_error& ex)
    {
        printf("%s", ex.what());
    }

    return false;
}

static bool U2A(const std::string& source, std::string& buffer)
{
    std::wstring temp;
    {
        if (U2W(source, temp) && W2A(temp, buffer))
        {
            return true;
        }
    }

    return false;
}

static bool A2U(const std::string& source, std::string& buffer)
{
    std::wstring temp;
    {
        if (A2W(source, temp) && W2U(temp, buffer))
        {
            return true;
        }
    }
    return false;
}

1.使用 cmake 生成 mysql 项目.
2.删除无关项目,仅留下以下列表项目文件(这11个项目文件编译出来的就是mysqlclient)
3.自行玻璃原有的第三方依赖库
4.添加项目并引用
5.8.0类似方法,自行去精简你的MySQL源代码吧。

说说抽取项目文件优点:
1.支持源码级调试,f12 未调试时可随时跟踪源代码。
2.减少项目依赖,让所有被依赖项成立树关系,减少工程配置项,使用项目引用。
3.你想到的我想不到,反正在windows下这种引用MySQLClient的方式,笔者认为更好。
4.减少MySQL自身大小,让这种关系在整个项目中被编译器优化。

- 1. libmysql\vsprojects\libmysql\authentication_win\auth_win_client.vcxproj
- 2. libmysql\vsprojects\libmysql\clientlib.vcxproj
- 3. libmysql\vsprojects\extra\comp_err.vcxproj
- 4. libmysql\vsprojects\dbug\dbug.vcxproj
- 5. libmysql\vsprojects\libmysql\libmysql.vcxproj
- 6. libmysql\vsprojects\mysys\mysys.vcxproj
- 7. libmysql\vsprojects\mysys_ssl\mysys_ssl.vcxproj         -- 依赖 OpenSSL
- 8. libmysql\vsprojects\strings\strings.vcxproj
- 9. libmysql\vsprojects\vio\vio.vcxproj
- 10. libmysql\vsprojects\zlib\zlib.vcxproj                  -- 可替换
- 11. libmysql\vsprojects\extra\zlib_decompress.vcxproj      -- 可删除

关系顺序

MySQL -> OpenSSL -> Zlib
Curl -> OpenSSl -> Zlib
我的项目 -> OpenSSL -> Zlib

最终成为: 我的项目 -> MySQL -> CURL -> OpenSSL -> Zlib

妈的,打了一大堆的字,提交发布文章的时候,提示error 500. 当时就是一个wocao。重新打。

前言:公司需要一个自动升级程序的环境,公司也不愿意花时间自己开发一个 http client 随后我就选择了 curl。
当然,我这里在编译 curl 的过程中疯狂踩坑了一周左右,因为我们公司的工控机盒子实在台low了。硬盘只有256M。

下面给出适用于 arm335x armv7l 系统的 正确编译参数

root@am335x:~/service# uname -a
Linux am335x 3.2.0 #595 Wed Jan 31 00:13:29 PST 2018 armv7l GNU/Linux

{mtitle title="CURL的编译参数"/}

./configure CC=/usr/bin/arm-none-linux-gnueabihf-gcc CXX=/usr/bin/arm-none-linux-gnueabihf-g++ AR=/usr/bin/arm-none-linux-gnueabihf-ar RANLIB=/usr/bin/arm-none-linux-gnueabihf-gcc-ranlib \
--host=arm-linux  \
--disable-shared --enable-static  \
--with-openssl \
--without-ssl \
--with-zlib=/home/dev/Projects/Shattrath/arm/include \
--with-libssh2=/home/dev/Projects/Shattrath/arm/include \
--enable-zlib \
--enable-ares \
--enable-threaded-resolver \
--enable-tls-srp  \
--enable-sspi \
--enable-dict \
--enable-ftp \
--enable-imap \
--disable-ldap \
--disable-ldaps \
--enable-pop3 \
--enable-proxy \
--disable-rtsp \
--enable-smtp \
--enable-telnet \
--enable-tftp \
--enable-ca-bundle \
--enable-gnutls \
--without-libidn \
--enable-librtmp \
--enable-nss \
--disable-ech \
--prefix=/home/dev/Projects/Shattrath/arm \
LDFLAGS="-L/home/dev/Projects/Shattrath/arm/lib -Wl,-rpath=/dynamic/ -Wl,--dynamic-linker=/dynamic/ld-linux-armhf.so.3" \
CPPFLAGS="-I/home/dev/Projects/Shattrath/arm/include -L/home/dev/Projects/Shattrath/arm/lib" \
LIBS="-lcares -lz -lssh2 -lssl -lcrypto -lpthread -ldl -lrt"

{mtitle title="OPENSSL的编译参数"/}

// https://blog.csdn.net/zhensansan/article/details/100976016
// https://bbs.csdn.net/topics/392316559
// 重点说一下:如果要实现一个交叉跨平台一定要使用 setarch linux32 或者 setarch i386 如果是64位的arm 就填写对应的平台,具体什么原因,我不知道,我菜了。
setarch linux32 ./config -Wl,-rpath=/dynamic/ -Wl,--dynamic-linker=/dynamic/ld-linux-armhf.so.3 no-asm -march=armv7-a -D__ARM_MAX_ARCH__=7 zlib \
--with-zlib-include=/home/dev/Projects/Shattrath/arm/include --with-zlib-lib=/home/dev/Projects/Shattrath/arm/lib \
--prefix=/home/dev/Projects/Shattrath/arm \
--openssldir=/home/dev/Projects/Shattrath/arm/openssl --cross-compile-prefix=arm-none-linux-gnueabihf-

说一下,为何我要这么麻烦,因为我不能远程调试啊,256M的硬盘无法安装gdb。不能远程调试,只能靠log log log。