简体   繁体   English

我如何与Cygwin玩得开心?

[英]How do I play nice with Cygwin?

I have a C/C++ program, written for Windows, and compiled with Visual Studio. 我有一个C / C ++程序,是为Windows编写的,并使用Visual Studio进行了编译。 And it's a command-line tool, which means that it could reasonably be run under Cygwin Bash, likely in MinTTY, and some of its users are now doing so. 而且它是一个命令行工具,这意味着它可以合理地在CyTwin Bash下运行(可能在MinTTY中运行),并且它的某些用户现在正在这样做。

I'd like to change my program to make it play nicer with Cygwin. 我想更改程序以使其在Cygwin中更好地播放。

My program currently uses the Windows Console APIs to output pretty colored text and to manage the cursor, and to generally be "interactive" (or "interactive" for a 1980s definition of "interactive"), at least when its output isn't being piped to a file. 我的程序当前使用Windows控制台API输出漂亮的彩色文本并管理光标,并且至少在没有输出时,通常是“交互式的”(对于1980年代的“交互式”定义是“交互式的”)。通过管道传输到文件。

To make my program play nicer with Cygwin, I can make it emit ANSI \\x1B[... escape codes instead of calling the Console APIs, but the real problem is knowing when to do so . 为了使我的程序在Cygwin中更好地发挥作用,我可以使它发出ANSI \\x1B[...转义代码,而不是调用控制台API,但是真正的问题是何时知道这样做


There are four cases, I think: 我认为有四种情况:

  1. Invoked as an interactive Windows console program. 作为交互式Windows控制台程序调用。 --> ( Use Console APIs. ) ->( 使用控制台API。

  2. Invoked as a normal Windows console program, but the user is piping its output somewhere. 作为普通的Windows控制台程序调用,但是用户将其输出传递到某个地方。 --> ( Emit no stylings or interactive calls at all. ) ->( 完全不发送样式或交互式呼叫。

  3. Invoked as an interactive program by Bash or under MinTTY. 由Bash或在MinTTY下作为交互式程序调用。 --> ( Use ANSI escape codes. ) ->( 使用ANSI转义码。

  4. Invoked by Bash, but the user is piping its output somewhere. 由Bash调用,但用户将其输出传递到某个地方。 --> ( Emit no stylings or interactive calls at all. ) ->( 完全不发送样式或交互式呼叫。

I can distinguish case 1 by testing whether GetConsoleMode() succeeds or fails for the stdout handle; 我可以通过测试GetConsoleMode()对于stdout句柄是成功还是失败来区分情况1; if it succeeds, I definitely have a Windows Console, and this is the case when I turn on the code to use the Console APIs. 如果成功,则肯定有一个Windows控制台,当我打开代码以使用控制台API时就是这种情况。

I'd like to treat case 3 differently and use the ANSI codes for it, but unfortunately, cases 2, 3, and 4 seem to be mostly indistinguishable: 我想对情况3进行不同的处理,并使用ANSI代码,但不幸的是,情况2、3和4似乎几乎无法区分:

  • The stdout handle seems to be just an opaque object of FILE_TYPE_PIPE for all three cases. 在所有这三种情况下, stdout句柄似乎只是FILE_TYPE_PIPE的不透明对象。
  • I can use the OSTYPE environment variable and at least guess that I'm under Cygwin, which distinguishes case 2 from cases 3 and 4. 我可以使用OSTYPE环境变量,并且至少可以猜到我在Cygwin的管理之下,该案例将案例2与案例3和4区分开来。
  • If I could link against cygwin1.dll , I could maybe somehow use its isatty() , but I can't link against that, since many of my users don't (and won't) have Cygwin installed. 如果我可以链接到cygwin1.dll ,则可以以某种方式使用它的isatty() ,但是我无法链接到cygwin1.dll ,因为许多用户没有(也不会)安装Cygwin。 (And I'm not at all convinced that'd work even if it was possible.) (即使有可能,我也不敢相信这会奏效 。)
  • MSVC's native _isatty() thinks Cygwin Bash is a pipe, not an interactive shell, because it just uses GetFileType() deep under the hood. MSVC的本机_isatty()认为Cygwin Bash是管道,而不是交互式外壳,因为它只在_isatty()使用了GetFileType()

In short, there's no obvious way I can see to separate case 3 from case 4. 简而言之,没有明显的方法可以将案例3与案例4分开。

Right now, I treat case 3 exactly like cases 2 and 4, and Cygwin users (myself included) get crappy glass teletype interaction instead of a friendly interactive full-screen display, and I'd really like to fix that. 现在,我将情况3和情况2和4完全一样对待,并且Cygwin用户(包括我自己)获得了glass脚的玻璃电传打字交互,而不是友好的交互式全屏显示,我真的很想解决这个问题。


So is there any way I can distinguish an interactive Cygwin invocation from other invocations, so my native-Windows program can behave nicely when invoked by Cygwin Bash or other similar shells? 那么,有什么方法可以将交互式 Cygwin调用与其他调用区分开来,从而使我的本机Windows程序在被Cygwin Bash或其他类似Shell调用时表现良好?

( Important note: There is one solution that's off the table: The program will not be compiled as a native Cygwin program. This is a Windows program, and it's compiled with the Microsoft tool chain, and it will not be compiled with GCC. The goal is to change/update it to behave as nicely under Cygwin as possible — without actually linking against any of the Cygwin DLLs. I can only reasonably distribute one executable file for Windows, not two.) 重要提示: 一个解决方案,就是假表:该计划将不会被编译为一个本地Cygwin的程序这是一个Windows程序,它的编制与微软的工具链,它不会与GCC编译的。我们的目标是更改/更新它,使其在Cygwin下表现得尽可能好-无需实际链接到任何Cygwin DLL。我只能为Windows合理分发一个可执行文件,而不能合理地分发两个。

If I could link against cygwin1.dll, I could maybe somehow use its isatty(), but I can't link against that, since many of my users don't (and won't) have Cygwin installed. 如果我可以链接到cygwin1.dll,则可以某种方式使用它的isatty(),但是我无法链接到cygwin1.dll,因为许多用户没有(也不会)安装Cygwin。 (And I'm not at all convinced that'd work even if it was possible.) (即使有可能,我也不敢相信这会奏效。)

Ok you cannot statically link against that DLL, but that doesn't mean that you cannot try to load it dynamically. 好的,您不能静态链接到该DLL,但这并不意味着您不能尝试动态加载它。

You could try to LoadLibrary("cygwin1.dll") . 您可以尝试LoadLibrary("cygwin1.dll") If it fails, then it's not running under cygwin, and you can use native Windows functions to detect console type. 如果失败,则说明它不在cygwin下运行,您可以使用Windows本机功能检测控制台类型。

On the other hand, if you can open that library (which means that Cygwin is available in the current system), then you are able to perform a dynamic call to isatty() and use the result to see if the output is redirected. 另一方面,如果您可以打开该库(这意味着Cygwin在当前系统中可用),则可以对isatty()进行动态调用,并使用结果查看输出是否被重定向。

Edit: it's not that easy to just load the cygwin DLL and call a function, you need to initialize the lib first as shown in this link 编辑:加载cygwin DLL并调用函数并不是那么容易,您需要首先初始化此链接所示的lib

An extract: 摘录:

static BOOL setup_root()
{
    HMODULE hCygwin = NULL;

    // Load the cygwin dll into our application.
    if(!load_cygwin_library(&hCygwin))
        return FALSE;

    // Init the cygwin environment. (Required)
    if(!init_cygwin_library(hCygwin))
        return FALSE;

with both interesting init routines. 与两个有趣的初始化例程。 If init_cygwin_library isn't called, further calls may not work: 如果未调用init_cygwin_library ,则进一步的调用可能不起作用:

static BOOL load_cygwin_library(HMODULE* hCygwin)
{
    if((*hCygwin = GetModuleHandleW(cyglibrary)) == NULL)
        if((*hCygwin = LoadLibraryW(cyglibrary)) == NULL)
            return FALSE;
    return TRUE;
}

static BOOL init_cygwin_library(HMODULE hCygwin)
{
    cygwin_dll_init_fn cygwin_dll_init = NULL;
    if((cygwin_dll_init = (cygwin_dll_init_fn)GetProcAddress(hCygwin,"cygwin_dll_init")) == NULL) {
        FreeLibrary(hCygwin);
        return FALSE;
    }
    cygwin_dll_init();
    return TRUE;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM