【问题标题】:CMake -- C -- Multiple Source Files Ignores Header GuardCMake -- C -- Multiple Source Files Ignores Header Guard
【发布时间】:2014-07-25 18:00:55
【问题描述】:

好的,所以我一直在尝试使用 CMake 和 Gtk。经过相当多的无用文档的艰难跋涉后,我终于用 Gtk 等正确编译了它。 像往常一样,我从一个定义了一个回调函数的文件开始我的项目,只是为了测试一些基本功能。但是,我通常将我的程序拆分为多个文件,每个文件一个函数,并创建一个带有包含所有原型的包含保护的公共头。 这对我来说基本上是标准程序,过去我已经做过很多次了,没有任何问题。 但是,不知何故,我的 CMake 过程正在做一些我不明白的事情(嗯,很多事情),并且我收到以下错误:

CMakeFiles/gte.dir/src/main.c.o:在函数gte_handler_about': main.c:(.text+0xb0): multiple definition ofgte_handler_about' CMakeFiles/gte.dir/src/gte_handler_about.c.o:gte_handler_about.c:(.text+0x0): 首先定义在这里 collect2:错误:ld 返回 1 个退出状态

main.c 文件相当简单,只需用 gtk_builder 加载一个 glade ui 文件并呈现它:

#  include "gtk/gtk.h"
#  include "gtksourceview/gtksourceview.h"
#  include "gte.h"

int main( int argc, char* argv[] )
{
    GtkWidget   *wGTEMain;
    GtkBuilder  *bGTEMain;
    GError      *eGTE;

    gtk_init( &argc, &argv );

    bGTEMain = gtk_builder_new();   

    gtk_builder_add_from_file( bGTEMain, "gte.glade", &eGTE );
    wGTEMain = GTK_WIDGET (gtk_builder_get_object ( bGTEMain, "GTEMain" ));
    gtk_builder_connect_signals ( bGTEMain, NULL ); 

    g_object_unref( G_OBJECT( bGTEMain));

    gtk_widget_show( wGTEMain );

    gtk_main();

    return 0;
}

当我开始在我的界面中使用该小部件时,我已经包含了 gtksourceview.h。

glade 文件非常标准,只包含两个信号,一个用于自动的 gtk_main_quit,另一个用于 gte_handler_about。我会在最后加入。

我以通常的方式创建了 gte.h,并带有一些独特的标头保护,如下所示:

#ifndef PSKT_INCLUDE_GTE_H__
#  define PSKT_INCLUDE_GTE_H__ 1

G_MODULE_EXPORT void gte_handler_about( GtkWidget *widget, gpointer data );

#endif /* PSKT_INCLUDE_GTE_H__ */

我已经使用 G_MODULE_EXPORT,因为我已经阅读过它们在 win32 平台上是必需的。我通常不会为宏指定一个明确的值,但我在测试中这样做了,看看这是否有所作为。 (它没有)。 最初我在这个文件中也有 gtk 头文件,但我想得更好,并将它们移回源文件。

然后,当然,我有我的单个函数,about 回调,它只是从 glade ui 文件中加载一个 gtk about 框:

#include "gtk/gtk.h"
#include "gte.h"

G_MODULE_EXPORT void gte_handler_about( GtkWidget *widget, gpointer data )
{
    GtkWidget   *wGTEAbout;
    GtkBuilder  *bGTEAbout;

    bGTEAbout = gtk_builder_new();
    gtk_builder_add_from_file( bGTEAbout, "gte.glade", NULL );

    wGTEAbout = GTK_WIDGET( gtk_builder_get_object( bGTEAbout, "GTEAbout" ) );

    gtk_dialog_run( GTK_DIALOG( wGTEAbout ) );

    g_object_unref( G_OBJECT( bGTEAbout ) );
    gtk_widget_destroy( wGTEAbout );
}

目前我并不太担心任何预加载或优化,并且该函数在 main.c 文件中时可以正常工作,并且原型位于 main 函数之上。

CMakeLists.txt 如下:

find_package(PkgConfig)
pkg_check_modules(DEPS REQUIRED
    gmodule-2.0
    gtk+-3.0
    gtksourceview-3.0
)

SET(CFLAGS
    ${DEPS_CFLAGS} ${DEPS_CFLAGS_OTHER}
)
SET(LIB_PATHS
    ${DEPS_LIBRARY_DIRS}
)

add_definitions(${CFLAGS})
link_directories(${LIB_PATHS})
link_libraries( gte ${DEPS_LIBRARIES} )

file(GLOB_RECURSE SRC_FILES src/*.c)

ADD_EXECUTABLE( gte ${SRC_FILES} )

我应该注意到我花了 才达到这一点。我在使用 link_libraries 部分时遇到了问题。我应该注意,我只在最后添加了文件(GLOB_RECURSE ...),以避免在 ADD_EXECUTABLE 中单独列出文件,而且我现在并不担心秘密注入的源文件。

THEN 刚才作为健全性检查,我刚刚尝试了以下命令,但它们也失败了,让我相信我真的只是变成了一个白痴,不再知道无论如何编码,这可能根本不是 CMAKE 问题。 (反引号是正确的,但是当我引用命令时它们似乎没有出现......

gcc -c gte_handler_about.c pkg-config --cflags gmodule-2.0 gtk+-3.0 gtksourceview-3.0

gcc -c main.c pkg-config --cflags gmodule-2.0 gtk+-3.0 gtksourceview-3.0

gcc -o gte main.o gte_handler_about.o pkg-config --libs gtk+-3.0 gtksourceview-3.0

gte_handler_about.o:在函数gte_handler_about': gte_handler_about.c:(.text+0x0): multiple definition ofgte_handler_about' main.o:main.c:(.text+0xb0): 首先定义在这里 collect2:错误:ld 返回 1 个退出状态

在过去,我似乎从 .o 文件构建档案没有问题,每个文件中都有单独的函数,所有函数都包括一个公共标题,如下所示:

# makefile
MYSRC= $(wildcard *.c)
MYOBJ= $(patsubst %c, %.o, $(MYSRC)

all: $(MYOBJ)
    ar -ru mya.a $(MYOBJ)

%.o: %.c
    gcc -Wall -O0 -g -c $^

然后编译没有问题:

gcc -o myut myut.c mya.a -lX11

.a 中的所有源代码均已编译,包括“mya.h”,myut.c 还包括“mya.h”,“mya.h”包括“X11/Xlib.h”。

我想我的问题真的是,我在这里做的和以前有什么不同?我只是需要睡觉,还是我编译 Gtk 的方式有什么不同?

对于 S&G,这里是 gte.glade 的 glade 文件:

<?xml version="1.0" encoding="UTF-8"?>
<interface>
<!-- interface-requires gtk+ 3.0 -->
<!-- interface-requires gtksourceview 3.0 -->
<object class="GtkAboutDialog" id="GTEAbout">
<property name="can_focus">False</property>
<property name="border_width">5</property>
<property name="title" translatable="yes">About Geoff's Text Editor</property>
<property name="resizable">False</property>
<property name="modal">True</property>
<property name="window_position">center-always</property>
<property name="type_hint">dialog</property>
<property name="has_resize_grip">False</property>
<property name="program_name">Geoff's Text Editor</property>
<property name="version">0.0.1.0</property>
<property name="copyright" translatable="yes">Copyright (c) 2014, polarysekt, kb3c.uX</property>
<property name="website">[redacted]</property>
<property name="authors">polarysekt</property>
<property name="license_type">gpl-3-0</property>
<child internal-child="vbox">
  <object class="GtkBox" id="aboutdialog-vbox1">
    <property name="can_focus">False</property>
    <property name="orientation">vertical</property>
    <property name="spacing">2</property>
    <child internal-child="action_area">
      <object class="GtkButtonBox" id="aboutdialog-action_area1">
        <property name="can_focus">False</property>
        <property name="layout_style">end</property>
      </object>
      <packing>
        <property name="expand">False</property>
        <property name="fill">True</property>
        <property name="pack_type">end</property>
        <property name="position">0</property>
      </packing>
    </child>
    <child>
      <placeholder/>
    </child>
  </object>
</child>
</object>
<object class="GtkWindow" id="GTEMain">
<property name="can_focus">False</property>
<property name="title" translatable="yes">GTEr</property>
<signal name="delete-event" handler="gtk_main_quit" swapped="no"/>
<child>
  <object class="GtkBox" id="box1">
    <property name="visible">True</property>
    <property name="can_focus">False</property>
    <property name="orientation">vertical</property>
    <child>
      <object class="GtkMenuBar" id="menubar1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <child>
          <object class="GtkMenuItem" id="menuitem1">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">_File</property>
            <property name="use_underline">True</property>
            <child type="submenu">
              <object class="GtkMenu" id="menu1">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <child>
                  <object class="GtkImageMenuItem" id="imagemenuitem1">
                    <property name="label">gtk-new</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                  </object>
                </child>
                <child>
                  <object class="GtkImageMenuItem" id="imagemenuitem2">
                    <property name="label">gtk-open</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                  </object>
                </child>
                <child>
                  <object class="GtkImageMenuItem" id="imagemenuitem3">
                    <property name="label">gtk-save</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                  </object>
                </child>
                <child>
                  <object class="GtkImageMenuItem" id="imagemenuitem4">
                    <property name="label">gtk-save-as</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                  </object>
                </child>
                <child>
                  <object class="GtkSeparatorMenuItem" id="separatormenuitem1">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                  </object>
                </child>
                <child>
                  <object class="GtkImageMenuItem" id="menuitem5">
                    <property name="label">gtk-media-rewind</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                    <child type="submenu">
                      <object class="GtkRecentChooserMenu" id="recentchoosermenu1">
                        <property name="visible">True</property>
                        <property name="can_focus">False</property>
                        <property name="limit">10</property>
                      </object>
                    </child>
                  </object>
                </child>
                <child>
                  <object class="GtkSeparatorMenuItem" id="separatormenuitem2">
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                  </object>
                </child>
                <child>
                  <object class="GtkImageMenuItem" id="imagemenuitem5">
                    <property name="label">gtk-quit</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                  </object>
                </child>
              </object>
            </child>
          </object>
        </child>
        <child>
          <object class="GtkMenuItem" id="menuitem2">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">_Edit</property>
            <property name="use_underline">True</property>
            <child type="submenu">
              <object class="GtkMenu" id="menu2">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <child>
                  <object class="GtkImageMenuItem" id="imagemenuitem6">
                    <property name="label">gtk-cut</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                  </object>
                </child>
                <child>
                  <object class="GtkImageMenuItem" id="imagemenuitem7">
                    <property name="label">gtk-copy</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                  </object>
                </child>
                <child>
                  <object class="GtkImageMenuItem" id="imagemenuitem8">
                    <property name="label">gtk-paste</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                  </object>
                </child>
                <child>
                  <object class="GtkImageMenuItem" id="imagemenuitem9">
                    <property name="label">gtk-delete</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                  </object>
                </child>
              </object>
            </child>
          </object>
        </child>
        <child>
          <object class="GtkMenuItem" id="menuitem3">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">_View</property>
            <property name="use_underline">True</property>
          </object>
        </child>
        <child>
          <object class="GtkMenuItem" id="mcAbout">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">_Help</property>
            <property name="use_underline">True</property>
            <child type="submenu">
              <object class="GtkMenu" id="menuAbout">
                <property name="visible">True</property>
                <property name="can_focus">False</property>
                <child>
                  <object class="GtkImageMenuItem" id="miAbout">
                    <property name="label">gtk-about</property>
                    <property name="visible">True</property>
                    <property name="can_focus">False</property>
                    <property name="use_underline">True</property>
                    <property name="use_stock">True</property>
                    <signal name="activate" handler="gte_handler_about" swapped="no"/>
                  </object>
                </child>
              </object>
            </child>
          </object>
        </child>
      </object>
      <packing>
        <property name="expand">False</property>
        <property name="fill">True</property>
        <property name="position">0</property>
      </packing>
    </child>
    <child>
      <object class="GtkToolbar" id="toolbar1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="toolbar_style">icons</property>
        <property name="icon_size">2</property>
        <child>
          <object class="GtkToolButton" id="tbbNew">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="has_tooltip">True</property>
            <property name="tooltip_markup" translatable="yes">New File</property>
            <property name="tooltip_text" translatable="yes">New File</property>
            <property name="label" translatable="yes">New</property>
            <property name="use_underline">True</property>
            <property name="stock_id">gtk-new</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="homogeneous">True</property>
          </packing>
        </child>
        <child>
          <object class="GtkToolButton" id="tbbLoad">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="has_tooltip">True</property>
            <property name="tooltip_markup" translatable="yes">Open File</property>
            <property name="tooltip_text" translatable="yes">Open File</property>
            <property name="label" translatable="yes">Load</property>
            <property name="use_underline">True</property>
            <property name="stock_id">gtk-open</property>
          </object>
          <packing>
            <property name="expand">False</property>
            <property name="homogeneous">True</property>
          </packing>
        </child>
      </object>
      <packing>
        <property name="expand">False</property>
        <property name="fill">True</property>
        <property name="position">1</property>
      </packing>
    </child>
    <child>
      <object class="GtkNotebook" id="notebook1">
        <property name="visible">True</property>
        <property name="can_focus">True</property>
        <property name="show_tabs">False</property>
        <child>
          <object class="GtkScrolledWindow" id="scrolledwindow1">
            <property name="visible">True</property>
            <property name="can_focus">True</property>
            <property name="shadow_type">in</property>
            <child>
              <object class="GtkSourceView" id="gtksourceview1">
                <property name="visible">True</property>
                <property name="can_focus">True</property>
                <property name="has_tooltip">True</property>
                <property name="left_margin">2</property>
                <property name="right_margin">2</property>
                <property name="show_line_numbers">True</property>
                <property name="tab_width">4</property>
                <property name="auto_indent">True</property>
                <property name="show_right_margin">True</property>
                <property name="right_margin_position">73</property>
                <property name="highlight_current_line">True</property>
                <property name="indent_on_tab">False</property>
              </object>
            </child>
          </object>
        </child>
        <child type="tab">
          <object class="GtkLabel" id="tab">
            <property name="visible">True</property>
            <property name="can_focus">False</property>
            <property name="label" translatable="yes">untitled1</property>
          </object>
          <packing>
            <property name="tab_fill">False</property>
          </packing>
        </child>
        <child>
          <placeholder/>
        </child>
        <child type="tab">
          <placeholder/>
        </child>
        <child>
          <placeholder/>
        </child>
        <child type="tab">
          <placeholder/>
        </child>
      </object>
      <packing>
        <property name="expand">True</property>
        <property name="fill">True</property>
        <property name="position">2</property>
      </packing>
    </child>
    <child>
      <object class="GtkStatusbar" id="statusbar1">
        <property name="visible">True</property>
        <property name="can_focus">False</property>
        <property name="orientation">vertical</property>
        <property name="spacing">2</property>
      </object>
      <packing>
        <property name="expand">False</property>
        <property name="fill">True</property>
        <property name="position">3</property>
      </packing>
    </child>
  </object>
</child>
</object>
</interface>

以及我用来运行 cmake 的 shell 脚本:

#! /bin/sh

mkdir -p build/
cd build/
cmake .. && make && cp ../res/gte.glade ./
cd ..

Grr,我知道这很简单和/或平凡,但我真的不能指望它......似乎每次我尝试使用某种平台工具包时都会发生类似的事情,并且我总是放弃并依赖 X/carbon/win32。

【问题讨论】:

  • 你能把gcc -E gte_handler_about.c `pkg-config --cflags gmodule-2.0 gtk+-3.0 gtksourceview-3.0`gcc -E main.c `pkg-config --cflags gmodule-2.0 gtk+-3.0 gtksourceview-3.0`的输出上传到gist.github.com(或类似的)
  • gist.github.com/polarysekt/21b9fe67bd3fa7d6ad4e 有趣...我看到 gte_handler_about 在两者中都扩展了...。不过,不完全知道这意味着什么,哈哈。感谢您的快速回复!
  • 你确定在 main.c 的末尾,没有get_handler_about 的定义吗?如果我对此有误,那么您能否将 2 个原始 c 文件也添加到 gist 中?
  • 另外,我认为您正在编辑的 main.c 与 cmake 正在使用的 main.c 不同。也许运行find . -name main.c 来查看是否有多个具有该名称的文件。
  • OMG...我的 main.c 仍然包含该函数,我正在编辑一个不同的文件!不知何故,我开始在项目根目录中编辑 main.c,而我原来的 main.c 仍在 src 中!不过,我想我不会从你的建议中弄清楚这一点。根据您的建议阅读 gcc -E 的输出后,我自己编译了 main.c 并按规定工作。我并不像我想的那样疯狂,但很接近!而且,当我输入此内容时,您回答的正是情况!

标签: c gcc linker cmake


【解决方案1】:

正如用户 sharth 所指出的,问题出在 main.c 文件上。

当我最初启动这个简单的测试应用程序时,我只是将我的main.c 和我的gte.glade 文件放在项目的根文件夹中,慢慢向外扩展。 一旦我正确加载了初始 GtkBuilder 对象(见下文),我就开始使用 cmake,因为这是这个小测试的另一个原因。

我立即注意到cmake 真的把我的文件夹弄得一团糟,因为我越来越接近工作,所以我遵循了我在其他此类项目中注意到的设计范式:lmmssimon 等。 . 并自动创建一个构建文件夹,并在该文件夹中运行cmake ..

一旦我更多地掌握了 cmake 的窍门,终于让 --cflags--libs 正常工作,因为以前我只在命令行或 makefile 中使用 pkg-config...

最难搞定的部分是link_libraries( ... ) 函数,我最初认为它是target_link_libraries(...),然后试图弄清楚要指定哪个参数。我最初尝试了$(GTK_LIBRARIES},但这似乎不够具体——然后是target_link_libraries(...) 函数的各种位置。

一旦我开始工作,我想开始进一步扩展我的小测试应用程序,我将源文件移动到 src/ 目录并开始使用它。然而,这不是我第一次犯这个错误,我浏览了各种文本编辑器......我有时会发现自己在命令行中快速使用nano,有时geditkate 区分开来,而我要么移植代码,要么并排比较不同的源代码。

在这种情况下,我之前在 kate 中打开了 main.c,但继续将文件移动到 src 目录中,而 kate 仍然指向原始目录。我在文件之间来回移动,我一定忽略了file has been changed on disk warning 并将我的新更改保存到原始文件中。同时,我从原始文件中删除了附加函数gte_handler_about(),并制作了两个新文件:gte_handler_about.cgte.h(带有标题保护),因为我更喜欢每个文件一个函数的方法。 [类似地,在使用 C++ 时,我发现自己很快就在头文件中使用内联函数破解类,直到它们成熟,然后将它们移动到单独的源文件中……一个存在明显错误的过程,如此处所示。]

无论如何,我得到了CMakeLists.txt 文件来支持这两个源文件,然后我开始收到链接器错误。在寻找可能的解决方案时,我遇到了file() 函数,并用通配符变量替换了文件列表......在黑暗中拍摄,因为它基本上做了同样的事情......

总之,解决方案通常是这样的,我来这里是为了寻找一组新鲜的眼睛。在团队中进行编码时,我经常发现那些看着你的家伙(或女孩)可以为错误和错误提供新的洞察力,尤其是在深夜,当我的视线模糊甚至咖啡失去效力时。

老实说,我还没有掌握gcc 的所有细节,因为我最近才开始搞乱-S 选项以在汇编步骤之前停止。

所以最后,我谦卑地来到这个网站(只有在用尽我的搜索引擎搜索所有可能的关键字组合并发布后)。

sharth 很快回复了大约 5 分钟,并建议(根据他的评论)我提供给 gcc 并输出到一个文件的 -E 参数,然后我将其上传到一个 gist,注意到但不知道做什么,main.c 输出中的冗余。

但是,他很好地指出我发布的代码与实际编译的代码可能存在差异,事实证明,这正是问题所在。尽管我的 cmet 和他的 cmet 之间有一些小的延迟(这是一个非常小的时间范围),但问题已经解决了,我的大部分头发都完好无损。

回想起来,最平凡的事情是多么令人沮丧,因为许多变量都在起作用。

本周早些时候,当我选择 glade 进行旋转时(我之前一直在代码中动态生成我的所有 gtk 小部件,尤其是菜单化,这非常乏味)——我被问题所困扰,我很快归因于我使用的是树莓派(我改用它来进行低级编码,因为我喜欢无风扇系统的舒适性,并且对于大多数应用程序,我不需要重型机器)......但是我是出现虚假的运行时错误,后来我将其归咎于为了释放我的 8GB 闪存上的一点空间而剔除了我系统的大部分内容。

无论如何,这不是Gtkcmake,而是普通的操作员错误。我喜欢 pi 的另一个原因是因为我通常不会因为正在运行的应用程序而将它卡住,这就是我在这里使用的特定机器上的情况。

【讨论】:

    猜你喜欢
    • 2011-02-21
    • 1970-01-01
    • 1970-01-01
    • 2023-02-20
    • 2018-03-10
    • 1970-01-01
    • 2012-12-07
    • 2014-10-26
    • 1970-01-01
    相关资源
    最近更新 更多