I am trying to deploy my Qt-based app under CMake. I used to use DeployQt5 in that way:
if (APPLE)
set (QT_QPA_PLUGIN ${QT_INSTALL_PLUGINS}/platforms/libqcocoa.dylib)
set (tgt_EXECUTABLE tgt.app)
elseif (WIN32 AND MSVC)
set (QT_QPA_PLUGIN ${QT_INSTALL_PLUGINS}/platforms/qwindows.dll)
get_property (tgt_EXECUTABLE TARGET tgt PROPERTY LOCATION)
get_filename_component (tgt_EXECUTABLE ${tgt_EXECUTABLE} NAME)
endif ()
set(CMAKE_INSTALL_SYSTEM_RUNTIME_DESTINATION ".")
include(InstallRequiredSystemLibraries)
include (DeployQt5)
install_qt5_executable ("${tgt_EXECUTABLE}"
"${QT_QPA_PLUGIN}" # qtplugins
"" # libs
"${QT_INSTALL_LIBS}" # dirs
)
but I don't like it. I want to use cmake's generator expressions and abandon the LOCATION property. I wonder if it is possible with the DeployQt5 module. It does not seem to be that straightforward:
include (DeployQt5)
install_qt5_executable ("$<TARGET_FILE:tgt>"
"${QT_QPA_PLUGIN}" # qtplugins
"" # libs
"${QT_INSTALL_LIBS}" # dirs
)
doesn't work. Is it possible to make that part of the CMakeLists.txt file cleaner?
Related
Long story short, I would like to create a Protocol Buffer object inside the initializePlugin(), defined in pluginMain.cpp as shown below:
// pluginMain.cpp
#include "hello.pb.h"
MStatus initializePlugin( MObject obj )
{
MGlobal::displayInfo( "Plugin is initialized!" );
hellopb_plugin::Foo f1;
return MStatus::kSuccess;
}
MStatus uninitializePlugin( MObject obj )
{
...
}
hellopb_plugin is a very simple protobuf type defined by the following hello.proto file:
// hello.proto
syntax = "proto3";
package hellopb_plugin;
message Foo
{
optional string name = 1;
}
The CMakeLists.txt I use includes the following:
cmake_minimum_required(VERSION 3.12)
if (NOT DEFINED CMAKE_TOOLCHAIN_FILE AND DEFINED ENV{CMAKE_TOOLCHAIN_FILE})
set(CMAKE_TOOLCHAIN_FILE $ENV{CMAKE_TOOLCHAIN_FILE})
endif()
project( Hello )
find_package( Protobuf REQUIRED )
include_directories( ${Protobuf_INCLUDE_DIRS} )
file( TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} PROTO_INPUT_PATH )
file( TO_NATIVE_PATH ${CMAKE_CURRENT_SOURCE_DIR} PROTO_OUTPUT_PATH )
file( GLOB PROTO_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.proto" )
foreach( proto ${PROTO_FILES})
file( TO_NATIVE_PATH ${proto} proto_native )
execute_process( COMMAND ${PROTOBUF_PROTOC_EXECUTABLE} --proto_path=${PROTO_INPUT_PATH} --cpp_out=${PROTO_OUTPUT_PATH} ${proto_native} )
endforeach()
file( GLOB HDRS "${CMAKE_CURRENT_SOURCE_DIR}/*.pb.h" )
file( GLOB SRCS "${CMAKE_CURRENT_SOURCE_DIR}/*.pb.cc" )
add_library( ${PROJECT_NAME}Proto ${HDRS} ${SRCS} )
link_libraries( ${PROJECT_NAME}Proto ${Protobuf_LIBRARIES} )
set( ${PROJECT_NAME}Proto_PATH ${PROJECT_NAME}Proto )
set( SOURCE_FILES pluginMain.cpp )
set( LIBRARIES OpenMaya OpenMayaUI OpenMayaAnim OpenMayaFX OpenMayaRender Foundation ${PROJECT_NAME}Proto )
include( $ENV{DEVKIT_LOCATION}/cmake/pluginEntry.cmake )
build_plugin()
Currently, the code builds, and links, fine when running cmake .. and cmake --build . --clean-first from a build/ inside the project folder, but the plugin cannot be loaded. The following error is shown in the script editor:
// Error: file: C:/.../Autodesk/Maya2022/scripts/others/pluginWin.mel line 934: Unable to dynamically load : C:/.../maya_plugin/build/Debug/Hello.mll
The specified module could not be found.
// Error: file: C:/.../Autodesk/Maya2022/scripts/others/pluginWin.mel line 934: The specified module could not be found.
(Hello) //
// Warning: file: C:/.../Autodesk/Maya2022/scripts/others/pluginWin.mel line 937: Could not load C:/.../maya_plugin/build/Debug/Hello.mll as a plug-in //
Although Hello.mll is created in the Debug/, it seems that there is a run-time problem that prevents the plugin from being loaded. As a test, I commented out the definition of f1 from the initialize_plugin() function, and the plugin was loaded successfully.
Q1: What is causing this problem?
Q2: Is the CMakeLists.txt file properly written to load Protocol Buffers?
Please note, that the CMakeLists.txt should not create an executable, as it's a plugin. Also, I am currently running Windows 10 and I have successfully installed Google's Protocol Buffers via vcpkg. To test the installation of the library, I created a similar example only as an executable, and it works properly.
[UPDATE]
It seems that protobuf_generate_cpp uses absolute paths.
Invoking protobuf compiler manually specifying relative path seems to generate valid sources.
Manual:
/usr/bin/protoc --cpp_out /home/pp/Projects/SmartHomeManagement/shm-iw/build shmiw/metadata/metadata.proto
produces: (metadata.pb.h)
::DescriptorTable descriptor_table_shmiw_2fmetadata_2fmetadata_2eproto;
Name contains subdirectories
Whereas when compiling by protobuf_generate_cpp from cmake, it invokes protobuf compiler with command:
/usr/bin/protoc --cpp_out /home/pp/Projects/SmartHomeManagement/shm-iw/build -I /home/pp/Projects/SmartHomeManagement/shm-iw/shmiw/metadata /home/pp/Projects/SmartHomeManagement/shm-iw/shmiw/metadata/metadata.proto
which produces "invalid" names that can't be used later on by other packages: (metadata.pb.h)
::DescriptorTable descriptor_table_metadata_2eproto;
I've got some problem with protobuf. I've got 3 proto files. The first one is a proto file that contains an option that all other proto files use. All proto files are organized in the same structure, and each of them belongs to a separate package. I want to generate all .h and .cc files and then put them into one single static library.
Project structure is as follows:
/root-dir
-CMakeLists.txt (1)
-shm-iw/
- CMakeLists.txt (2)
- bci
- CMakeLists.txt (3)
- bci.proto
- icon
- CMakeLists.txt (4)
- icon.proto
- metadata
- CMakeLists.txt (5)
- metadata.proto
Root CMakeLists.txt (1)
cmake_minimum_required(VERSION 3.12)
project(shm-iw CXX)
set(SHM-IW_VERSION 0.1)
find_package(Protobuf REQUIRED)
include_directories(${CMAKE_BINARY_DIR})
set (Protobuf_IMPORT_DIRS ${CMAKE_SOURCE_DIR} )
add_subdirectory(shm-iw)
shm-iw CMakeLists.txt (2)
cmake_minimum_required(VERSION 3.12)
add_subdirectory(metadata)
add_subdirectory(bci)
add_subdirectory(icon)
bci CMakeLists.txt (3)
cmake_minimum_required(VERSION 3.12)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS
bci.proto
)
add_library(bci_objlib OBJECT
${PROTO_SRCS}
${PROTO_HDRS}
)
target_link_libraries(bci_objlib metadata_objlib)
add_dependencies(bci_objlib metadata_objlib)
bci.proto
syntax = "proto3";
/* Board Control Interface */
import "shmiw/metadata/metadata.proto"; //Note the path to metadata.proto
package shm.iw.bci;
enum IndicatorType {
Status = 0;
Warning = 1;
Maintenance = 2;
Fault = 3;
}
enum IndicatorState {
SteadyOff = 0;
SteadyOn = 1;
Blink = 2;
};
message GetVisualIndicationReq
{
option (shm.iw.metadata.MESSAGE_NUMBER) = 0x1000101;
IndicatorType indicator = 1;
}
message GetVisualIndicationCfm
{
option (shm.iw.metadata.MESSAGE_NUMBER) = 0x1000102;
IndicatorType indicator = 1;
IndicatorState state = 2;
}
metadata CMakeLists.txt (5)
cmake_minimum_required(VERSION 3.12)
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS
metadata.proto
)
add_library(metadata_objlib OBJECT
${PROTO_SRCS}
${PROTO_HDRS}
)
metadata.proto
syntax = "proto3";
import "google/protobuf/descriptor.proto";
package shm.iw.metadata;
extend google.protobuf.MessageOptions {
uint32 MESSAGE_NUMBER = 50001;
}
I skipped icon directory as it's almost the same as bci directory, they just have different messages but it's not relevant now.
When I'm compiling I'm getting an error
shm-iw/build/shm-iw/bci/bci.pb.cc:183:6: error: ‘::descriptor_table_shm_2diw_2fmetadata_2fmetadata_2eproto’ has not been declared
183 | &::descriptor_table_shmiw_2fmetadata_2fmetadata_2eproto,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Looking at the metadata.pb.h we've got something like this:
extern const ::PROTOBUF_NAMESPACE_ID::internal::DescriptorTable descriptor_table_metadata_2eproto;
Let's compare the name of the missing declaration and the declaration generated in metadata.pb.h
metadata.pb.h: descriptor_table_metadata_2eproto
bci.pb.c: descriptor_table_shmiw_2fmetadata_2fmetadata_2eproto
They look very similar to each other, but the second one has a few additional words: shm, iw, metadata, which seem to correspond to import path defined in bci.proto
import "shmiw/metadata/metadata.proto";
What's the reason why it happens? Why does the protobuf compiler not generate the metadata's "decriptor_tabele*" accordingly to the package which is defined in metadata.proto?
Protoc handling of path names is pretty confusing, but here are the basics:
Input file names are separated to include dir and relative path.
Relative path determines the name of the symbols that go into generated files.
Include dir must match a directory given with -I.
If no -I arguments are given, there is always an implicit -I .
Based on this, we can figure out why it works the way it works for you:
Case 1: relative path
/usr/bin/protoc
--cpp_out /home/pp/Projects/SmartHomeManagement/shm-iw/build
shmiw/metadata/metadata.proto
No -I is given, so -I . is assumed. The relative path is shmiw/metadata/metadata.proto, giving the symbol name of descriptor_table_shmiw_2fmetadata_2fmetadata_2eproto. The 2f and 2e stand for / and . which are not valid in symbol names.
Case 2: absolute path
/usr/bin/protoc
--cpp_out /home/pp/Projects/SmartHomeManagement/shm-iw/build
-I /home/pp/Projects/SmartHomeManagement/shm-iw/shmiw/metadata
/home/pp/Projects/SmartHomeManagement/shm-iw/shmiw/metadata/metadata.proto
Now the path relative to -I directory is just metadata.proto. Thus you get descriptor_table_metadata_2eproto as the symbol name.
Case 3: absolute path, but same symbol name as case 1
/usr/bin/protoc
--cpp_out /home/pp/Projects/SmartHomeManagement/shm-iw/build
-I /home/pp/Projects/SmartHomeManagement/shm-iw
/home/pp/Projects/SmartHomeManagement/shm-iw/shmiw/metadata/metadata.proto
After this simple change to -I directory, it will give the same symbol name as in case 1.
I am creating a few C++ libraries in a project (solution in VS terminology) that needs to be used by two other projects. For this I created a FindDQSAnalyticsInfra.cmake file which is as follows:
# DQSAnalyticsInfra
# -----
# Find the path to DQSAnalyticsInfra header files and libraries
#
# DEFINES
# ------
# DQSINFRA_ROOT - Root of the DQSAnalyticsInfra project
# DQSINFRA_INCLUDE_DIR - DQSAnalyticsInfra include directory
# DQSINFRA_LIBRARIES - Libraries required to link DQSAnalyticsInfra
# DQSINFRA_FOUND - Confirmation
set(DQSINFRA_LIBRARIES_LIST Utils Actor gtest)
find_path(DQSINFRA_INCLUDE_DIR Actor/Actor.h Utils/Log.h gtest/gtest/gtest.h
${DQSINFRA_ROOT}/include
)
foreach(search_lib ${DQSINFRA_LIBRARIES_LIST})
find_library(DQSINFRA_LIB NAMES ${search_lib}
PATHS
${DQSINFRA_ROOT}/lib/Release #The problem is here
)
set(DQSINFRA_LIBRARIES ${DQSINFRA_LIBRARIES} ${DQSINFRA_LIB})
if(DQSINFRA_LIB)
unset(DQSINFRA_LIB CACHE)
set(DQSINFRA_FOUND TRUE)
else(DQSINFRA_LIB)
set(DQSINFRA_FOUND FALSE)
break()
endif(DQSINFRA_LIB)
endforeach(search_lib)
if(DQSINFRA_INCLUDE_DIR AND DQSINFRA_LIBRARIES AND DQSINFRA_FOUND)
set(DQSINFRA_FOUND TRUE)
message(STATUS "Found DQSAnalyticsInfra. ")
message(STATUS "Include Path: ${DQSINFRA_INCLUDE_DIR}")
message(STATUS "Libraries ${DQSINFRA_LIBRARIES}")
else(DQSINFRA_INCLUDE_DIR AND DQSINFRA_LIBRARIES AND DQSINFRA_FOUND)
set(DQSINFRA_FOUND FALSE)
message(STATUS "DQSAnalyticsInfra not found.")
endif(DQSINFRA_INCLUDE_DIR AND DQSINFRA_LIBRARIES AND DQSINFRA_FOUND)
mark_as_advanced(DQSINFRA_INCLUDE_DIR DQSINFRA_LIBRARIES)
This file works fine. The issue is that in the find_library command used in this file, I am hardcoding the path as ${DQSINFRA_ROOT}/lib/Release. This mean that I cannot use this file to link to Debug builds (I have to manually change the file to use ${DQSINFRA_ROOT}/lib/Debug). Any idea on how this can be fixed.Thanks.
Use debug and optimized keywords that can be specified for target_link_libraries:
find_library(DQSINFRA_LIB_DEBUG NAMES ${search_lib}
PATHS
${DQSINFRA_ROOT}/lib/Debug
)
find_library(DQSINFRA_LIB_RELEASE NAMES ${search_lib}
PATHS
${DQSINFRA_ROOT}/lib/Release
)
set(DQSINFRA_LIBRARIES optimized ${DQSINFRA_LIB_RELEASE} debug ${DQSINFRA_LIB_DEBUG})
I have been trying to include the latest version of qextserialport into the project I am working on. The project structure is as below:
CameraProject
CameraProject.pro
CameraProject
Headers
Sources
qextserialport
Headers
Sources
My CMake file currently looks like so:
PROJECT(CameraProject)
FIND_PACKAGE(Qt4 REQUIRED)
FIND_LIBRARY(SIMPLONLIB lv.simplon lib)
FIND_LIBRARY(SIMPLONIMGPROC lv.simplon.imgproc lib)
SET(CameraProject_SOURCES include/lv.simplon.class.cpp camera.cpp main.cpp mainwindow.cpp osdep.cpp paint.cpp)
SET(CameraProject_HEADERS include/lv.simplon.class.h camera.h mainwindow.h osdep.h paint.h)
SET(CameraProject_RESOURCES icons.qrc)
INCLUDE(${QT_USE_FILE})
ADD_DEFINITIONS(${QT_DEFINITIONS})
ADD_EXECUTABLE(CameraProject ${CameraProject_SOURCES}
${CameraProject_HEADERS_MOC}
${CameraProject_RESOURCES_RCC})
TARGET_LINK_LIBRARIES(CameraProject ${QT_LIBRARIES} ${SIMPLONLIB} ${SIMPLONIMGPROC})
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR} include QExtSerialPort/src)
And despite including the QextSerialPort files in the Include Directories, I get linker issues being drawn.
EDIT: More information!
Found here is the qextserialport.pri file that is included in CameraProject.pro like so: include(./QExtSerialPort/src/qextserialport.pri)
Should I be making a second CMakeLists file for the qextserialport library placed within the source folder?
Any input would be greatly appreciated, please do not hesitate to request for clarification or any further information.
What did for qxt is to use a cmake finder module instead of directly including the code into my projects. I then built qxt with qmake and let CMake find the libraries it creates.
#############
## basic FindQxt.cmake
## This is an *EXTREMELY BASIC* cmake find/config file for
## those times you have a cmake project and wish to use
## libQxt.
##
## It should be noted that at the time of writing, that
## I (mschnee) have an extremely limited understanding of the
## way Find*.cmake files work, but I have attempted to
## emulate what FindQt4.cmake and a few others do.
##
## To enable a specific component, set your QXT_USE_${modname}:
## SET(QXT_USE_QXTCORE TRUE)
## SET(QXT_USE_QXTGUI FALSE)
## Currently available components:
## QxtCore, QxtGui, QxtNetwork, QxtWeb, QxtSql
## Auto-including directories are enabled with INCLUDE_DIRECTORIES(), but
## can be accessed if necessary via ${QXT_INCLUDE_DIRS}
##
## To add the libraries to your build, TARGET_LINK_LIBRARIES(), such as...
## TARGET_LINK_LIBRARIES(YourTargetNameHere ${QXT_LIBRARIES})
## ...or..
## TARGET_LINK_LIBRARIES(YourTargetNameHere ${QT_LIBRARIES} ${QXT_LIBRARIES})
################### TODO:
## The purpose of this cmake file is to find what components
## exist, regardless of how libQxt was build or configured, thus
## it should search/find all possible options. As I am not aware
## that any module requires anything special to be used, adding all
## modules to ${QXT_MODULES} below should be sufficient.
## Eventually, there should be version numbers, but
## I am still too unfamiliar with cmake to determine how to do
## version checks and comparisons.
## At the moment, this cmake returns a failure if you
## try to use a component that doesn't exist. I don't know how to
## set up warnings.
## It would be nice having a FindQxt.cmake and a UseQxt.cmake
## file like done for Qt - one to check for everything in advance
##############
###### setup
SET(QXT_MODULES QxtGui QxtWeb QxtZeroConf QxtNetwork QxtSql QxtBerkeley QxtCore)
SET(QXT_FOUND_MODULES)
FOREACH(mod ${QXT_MODULES})
STRING(TOUPPER ${mod} U_MOD)
SET(QXT_${U_MOD}_INCLUDE_DIR NOTFOUND)
SET(QXT_${U_MOD}_LIB_DEBUG NOTFOUND)
SET(QXT_${U_MOD}_LIB_RELEASE NOTFOUND)
SET(QXT_FOUND_${U_MOD} FALSE)
ENDFOREACH(mod)
SET(QXT_QXTGUI_DEPENDSON QxtCore)
SET(QXT_QXTWEB_DEPENDSON QxtCore QxtNetwork)
SET(QXT_QXTZEROCONF_DEPENDSON QxtCore QxtNetwork)
SET(QXT_QXTNETWORK_DEPENDSON QxtCore)
SET(QXT_QXTQSQL_DEPENDSON QxtCore)
SET(QXT_QXTBERKELEY_DEPENDSON QxtCore)
FIND_PATH(QXT_DIR libqxt.pro Qxt/include/QxtCore/Qxt)
FIND_PATH(QXT_BINARY_DIR
NAMES QxtCore.dll QxtCored.dll
PATHS
${QXT_DIR}/bin
${QXT_DIR}/Bin
NO_DEFAULT_PATH
)
#SET(QXT_BINARY_DIR "${QXT_DIR}/bin" CACHE PATH "${QXT_DIR}/bin")
FOREACH(mod ${QXT_MODULES})
STRING(TOUPPER ${mod} U_MOD)
FIND_PATH(QXT_${U_MOD}_INCLUDE_DIR ${mod}
PATH_SUFFIXES ${mod} include/${mod} Qxt/include/${mod} include/Qxt/${mod}
PATHS
~/Library/Frameworks/
/Library/Frameworks/
/sw/
/usr/local/
/usr
/opt/local/
/opt/csw
/opt
"C:\\"
"C:\\Program Files\\"
"C:\\Program Files(x86)\\"
${QXT_DIR}
NO_DEFAULT_PATH
)
FIND_LIBRARY(QXT_${U_MOD}_LIB_RELEASE NAME ${mod}
PATH_SUFFIXES Qxt/lib64 Qxt/lib lib64 lib
PATHS
/sw
/usr/local
/usr
/opt/local
/opt/csw
/opt
"C:\\"
"C:\\Program Files"
"C:\\Program Files(x86)"
${QXT_DIR}
NO_DEFAULT_PATH
)
FIND_LIBRARY(QXT_${U_MOD}_LIB_DEBUG NAME ${mod}d
PATH_SUFFIXES Qxt/lib64 Qxt/lib lib64 lib
PATHS
/sw
/usr/local
/usr
/opt/local
/opt/csw
/opt
"C:\\"
"C:\\Program Files"
"C:\\Program Files(x86)"
${QXT_DIR}
NO_DEFAULT_PATH
)
IF (QXT_${U_MOD}_LIB_RELEASE)
SET(QXT_FOUND_MODULES "${QXT_FOUND_MODULES} ${mod}")
ENDIF (QXT_${U_MOD}_LIB_RELEASE)
IF (QXT_${U_MOD}_LIB_DEBUG)
SET(QXT_FOUND_MODULES "${QXT_FOUND_MODULES} ${mod}")
ENDIF (QXT_${U_MOD}_LIB_DEBUG)
ENDFOREACH(mod)
FOREACH(mod ${QXT_MODULES})
STRING(TOUPPER ${mod} U_MOD)
IF(QXT_${U_MOD}_INCLUDE_DIR AND QXT_${U_MOD}_LIB_RELEASE)
SET(QXT_FOUND_${U_MOD} TRUE)
ENDIF(QXT_${U_MOD}_INCLUDE_DIR AND QXT_${U_MOD}_LIB_RELEASE)
ENDFOREACH(mod)
##### find and include
# To use a Qxt Library....
# SET(QXT_FIND_COMPONENTS QxtCore, QxtGui)
# ...and this will do the rest
IF( QXT_FIND_COMPONENTS )
FOREACH( component ${QXT_FIND_COMPONENTS} )
STRING( TOUPPER ${component} _COMPONENT )
SET(QXT_USE_${_COMPONENT}_COMPONENT TRUE)
ENDFOREACH( component )
ENDIF( QXT_FIND_COMPONENTS )
SET(QXT_LIBRARIES "")
SET(QXT_INCLUDE_DIRS "")
# like FindQt4.cmake, in order of dependence
FOREACH( module ${QXT_MODULES} )
STRING(TOUPPER ${module} U_MOD)
IF(QXT_USE_${U_MOD} OR QXT_DEPENDS_${U_MOD})
IF(QXT_FOUND_${U_MOD})
STRING(REPLACE "QXT" "" qxt_module_def "${U_MOD}")
ADD_DEFINITIONS(-DQXT_${qxt_module_def}_LIB)
SET(QXT_INCLUDE_DIRS ${QXT_INCLUDE_DIRS} ${QXT_${U_MOD}_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${QXT_${U_MOD}_INCLUDE_DIR})
SET(QXT_LIBRARIES ${QXT_LIBRARIES};optimized;${QXT_${U_MOD}_LIB_RELEASE};debug;${QXT_${U_MOD}_LIB_DEBUG})
ELSE(QXT_FOUND_${U_MOD})
MESSAGE("Could not find Qxt Module ${module}")
RETURN()
ENDIF(QXT_FOUND_${U_MOD})
FOREACH(dep QXT_${U_MOD}_DEPENDSON)
SET(QXT_DEPENDS_${dep} TRUE)
ENDFOREACH(dep)
ENDIF(QXT_USE_${U_MOD} OR QXT_DEPENDS_${U_MOD})
ENDFOREACH(module)
MESSAGE(STATUS "Found Qxt Libraries:${QXT_FOUND_MODULES}")
MESSAGE(STATUS "Include directories:${QXT_INCLUDE_DIRS}")
I put this module in a sub directory of my root project called CMake/Modules and include it into cmake near the top of the root CMakeLists.txt using the following command:
# The following line will add additional finders to CMake without the need to be placed in the CMake install path
LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake/Modules)
And finally to have CMake find Qxt
SET(QXT_FIND_COMPONENTS QxtCore, QxtGui)
SET(QXT_USE_QXTCORE TRUE)
FIND_PACKAGE(Qxt REQUIRED)
I have the following code... which is throwing a main.cpp:18: undefined reference to phrase_init() Coming from C# experience C is a bit annoying especially when trying to figure out where the problem is :( Any idea or pointer will be greatly appreciated!
phrase.h:
#ifndef PHRASE_H
#define PHRASE_H
typedef struct
{
char* Word1;
char* Word2;
} Phrase;
Phrase* phrase_init(void);
#endif
Phrase.c :
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include "phrase.h"
Phrase* phrase_init()
{
Phrase* phrase = (Phrase *)malloc(sizeof(Phrase));
phrase->Word1 = (char *)malloc(sizeof(char));
phrase->Word2 = (char *)malloc(sizeof(char));
return phrase;
}
main.c
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <cctype>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include "phrase.h"
int main(int argc, char** argv) {
char* word1 = "Testing";
char* word2 = "Word2";
Phrase* test = phrase_init();
strcpy(test->Word1, word1);
strcpy(test->Word2, word2);
printf("Word 1: %s", test->Word1);
printf("Word 2: %s", test->Word2);
scanf("%s", word1);
}
Makefile:
#
# There exist several targets which are by default empty and which can be
# used for execution of your targets. These targets are usually executed
# before and after some main targets. They are:
#
# .build-pre: called before 'build' target
# .build-post: called after 'build' target
# .clean-pre: called before 'clean' target
# .clean-post: called after 'clean' target
# .clobber-pre: called before 'clobber' target
# .clobber-post: called after 'clobber' target
# .all-pre: called before 'all' target
# .all-post: called after 'all' target
# .help-pre: called before 'help' target
# .help-post: called after 'help' target
#
# Targets beginning with '.' are not intended to be called on their own.
#
# Main targets can be executed directly, and they are:
#
# build build a specific configuration
# clean remove built files from a configuration
# clobber remove all built files
# all build all configurations
# help print help mesage
#
# Targets .build-impl, .clean-impl, .clobber-impl, .all-impl, and
# .help-impl are implemented in nbproject/makefile-impl.mk.
#
# Available make variables:
#
# CND_BASEDIR base directory for relative paths
# CND_DISTDIR default top distribution directory (build artifacts)
# CND_BUILDDIR default top build directory (object files, ...)
# CONF name of current configuration
# CND_PLATFORM_${CONF} platform name (current configuration)
# CND_ARTIFACT_DIR_${CONF} directory of build artifact (current configuration)
# CND_ARTIFACT_NAME_${CONF} name of build artifact (current configuration)
# CND_ARTIFACT_PATH_${CONF} path to build artifact (current configuration)
# CND_PACKAGE_DIR_${CONF} directory of package (current configuration)
# CND_PACKAGE_NAME_${CONF} name of package (current configuration)
# CND_PACKAGE_PATH_${CONF} path to package (current configuration)
#
# NOCDDL
# Environment
MKDIR=mkdir
CP=cp
CCADMIN=CCadmin
# build
build: .build-post
.build-pre:
# Add your pre 'build' code here...
.build-post: .build-impl
# Add your post 'build' code here...
# clean
clean: .clean-post
.clean-pre:
# Add your pre 'clean' code here...
.clean-post: .clean-impl
# Add your post 'clean' code here...
# clobber
clobber: .clobber-post
.clobber-pre:
# Add your pre 'clobber' code here...
.clobber-post: .clobber-impl
# Add your post 'clobber' code here...
# all
all: .all-post
.all-pre:
# Add your pre 'all' code here...
.all-post: .all-impl
# Add your post 'all' code here...
# build tests
build-tests: .build-tests-post
.build-tests-pre:
# Add your pre 'build-tests' code here...
.build-tests-post: .build-tests-impl
# Add your post 'build-tests' code here...
# run tests
test: .test-post
.test-pre:
# Add your pre 'test' code here...
.test-post: .test-impl
# Add your post 'test' code here...
# help
help: .help-post
.help-pre:
# Add your pre 'help' code here...
.help-post: .help-impl
# Add your post 'help' code here...
# include project implementation makefile
include nbproject/Makefile-impl.mk
# include project make variables
include nbproject/Makefile-variables.mk
You have to tell the linker where to find the symbol.
For example:
g++ -c phrase.cpp # creates phrase.o which defines phrase_init()
g++ -c main.cpp # creates main.o which refers to phrase_init()
g++ phrase.o main.o -o main # creates executable file "main"
Or, to do all of the above in one command:
g++ phrase.cpp main.cpp -o main
Note that I'm assuming both source files are C++, and are named with .cpp extensions. Your question refers to files with both .c and .cpp extensions, and the question is tagged c++.
If you're using C, then you shouldn't be using C++-specific headers in main.c, and you should use gcc rather than g++.
If you're using C++, all your source files should have .cpp suffixes and you should used g++.
And if you're trying to mix C and C++, then you should be using extern "C" so the compiler knows what you're doing (but it's usually easier to use pure C++).
And you really should compile with -Wall -g so add to your Makefile
CXXFLAGS+= -Wall -g
CFLAGS+= -Wall -g
the first is for C++, the second is for C
I also think you should write by hand your own (simpler) Makefile for make (instead of copying a more complex Makefile that you don't understand).