Search code examples
makefilecmakeclion

Generate then use source file using CMake in CLion


I'm trying to work on a project in CLion using Gtk+, but the CMake file I came up with to make it work seems overly complex and bad. It also puts a generated source file in the binaries folder, so I want to know if there's a better way of doing this.

I wrote a Makefile to demonstrate how I want CMake to behave:

CC ?= gcc
PKGCONFIG = $(shell which pkg-config)
CFLAGS = $(shell $(PKGCONFIG) --cflags gtk+-3.0)
LIBS = $(shell $(PKGCONFIG) --libs gtk+-3.0)

SRC = main.c labpresentapp.c labpresentappwin.c
GEN_SRC = resources.c

OBJDIR := objdir
OBJS := $(addprefix $(OBJDIR)/,$(SRC:.c=.o) $(GEN_SRC:.c=.o))

.PHONY=all clean

all: labpresentapp

resources.c: labpresentapp.gresource.xml window.ui app-menu.ui
        glib-compile-resources labpresentapp.gresource.xml --target=$@ --generate-source

$(OBJDIR)/%.o: %.c
        $(CC) -c -o $@ $(CFLAGS) $<

$(OBJS): | $(OBJDIR)

$(OBJDIR):
        mkdir $(OBJDIR)

labpresentapp: $(OBJS)
        $(CC) -o $(@F) $(OBJS) $(LIBS)

clean:
        rm -f $(SRC_GEN)
        rm -f $(OBJS)
        rm -rf $(OBJDIR)
        rm -f labpresentapp

However, I cannot get CMake to do this. Below is my latest attempt:

cmake_minimum_required(VERSION 3.14)
project(LabPresentApp C)

set(LAB_PRESENT_APP_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(LAB_PRESENT_APP_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})

set(LAB_PRESENT_APP_VERSION_MAJOR 1)
set(LAB_PRESENT_APP_VERSION_MINOR 0)
set(LAB_PRESENT_APP_VERSION_PATCH 0)

set(CMAKE_C_STANDARD 11)

find_package(PkgConfig REQUIRED)

pkg_check_modules(MY_PKG REQUIRED IMPORTED_TARGET gtk+-3.0)

set(GLIB_FLAGS --target=resources.c)
set(GLIB_FLAGS ${GLIB_FLAGS} --generate-source)
set(GLIB_FLAGS ${GLIB_FLAGS} --sourcedir=${PROJECT_SOURCE_DIR})

add_custom_command(
        OUTPUT resources.c
        COMMAND glib-compile-resources ${PROJECT_SOURCE_DIR}/labpresentapp.gresource.xml ${GLIB_FLAGS}
        DEPENDS ${PROJECT_SOURCE_DIR}/labpresentapp.gresource.xml ${PROJECT_SOURCE_DIR}/app-menu.ui
                ${PROJECT_SOURCE_DIR}/window.ui
)

add_custom_target(generate_resources DEPENDS resources.c)

set(SOURCE_FILES main.c labpresentapp.c labpresentapp.h labpresentappwin.c labpresentappwin.h resources.c)

add_executable(${PROJECT_NAME} ${SOURCE_FILES})

add_dependencies(${PROJECT_NAME} generate_resources)

target_link_libraries(${PROJECT_NAME} PUBLIC PkgConfig::MY_PKG)

This emulates most of the function of the Makefile, but resources.c is generated in the binary folder.

Is there a better way to accomplish the function of the Makefile in CMake?


Solution

  • Since your glib-compile-resources does not specify where to generate the file, it is being generated in current working directory. As CMake documentation states:

    WORKING_DIRECTORY

    Execute the command with the given current working directory. If it is a relative path it will be interpreted relative to the build tree directory corresponding to the current source directory.

    If you expect a file at a given location, you would probably need to add WORKING_DIRECTORY directive to this add_custom_command to anchor the location at ${CMAKE_CURRENT_SOURCE_DIR}.

    Personally I would leave the behavior as is and make your sources line read:

    set(SOURCE_FILES main.c labpresentapp.c labpresentapp.h labpresentappwin.c labpresentappwin.h ${CMAKE_CURRENT_BINARY_DIR}/resources.c)
    

    I find this behavior correct. Source directory should be kept intact and generated files should go into binary directory. This way it prevents from accidental putting the generated file into source control and makes cleanup easier (it is enough to remove binary directory instead of purging single files across many locations).