Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft: Generate C/C++ CamelCase forwarding headers #462

Open
wants to merge 1 commit into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ message(STATUS "Configuring ${PROJECT_NAME} ${PROJECT_VERSION} ==>")

include(FeatureSummary)
include(CTest)
include(cmake/QuotientGenerateHeaders.cmake)

# https://github.com/quotient-im/libQuotient/issues/369
option(${PROJECT_NAME}_ENABLE_E2EE "end-to-end encryption (E2EE) support" OFF)
Expand Down Expand Up @@ -291,8 +292,9 @@ if (BUILD_TESTING)
add_subdirectory(autotests)
endif()

# Configure installation
add_subdirectory(lib)

# Configure installation
install(TARGETS ${PROJECT_NAME} EXPORT ${PROJECT_NAME}Targets
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
Expand Down
222 changes: 222 additions & 0 deletions cmake/QuotientGenerateHeaders.cmake
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
# SPDX-FileCopyrightText: 2013 Aleix Pol Gonzalez <[email protected]>
# SPDX-FileCopyrightText: 2014 Alex Merry <[email protected]>
# SPDX-FileCopyrightText: 2015 Patrick Spendrin <[email protected]>
#
# SPDX-License-Identifier: BSD-3-Clause

#[=======================================================================[.rst:
QUOTIENTGenerateHeaders
------------------

Generate C/C++ CamelCase forwarding headers.

::

quotient_generate_headers(<camelcase_forwarding_headers_var>
HEADER_NAMES <CamelCaseName> [<CamelCaseName> [...]]
[ORIGINAL <CAMELCASE|LOWERCASE>]
[HEADER_EXTENSION <header_extension>]
[OUTPUT_DIR <output_dir>]
[PREFIX <prefix>]
[REQUIRED_HEADERS <variable>]
[COMMON_HEADER <HeaderName>]
[RELATIVE <relative_path>])

For each CamelCase header name passed to HEADER_NAMES, a file of that name
will be generated that will include a version with ``.h`` or, if set,
``.<header_extension>`` appended.
For example, the generated header ``ClassA`` will include ``classa.h`` (or
``ClassA.h``, see ORIGINAL).
If a CamelCaseName consists of multiple comma-separated files, e.g.
``ClassA,ClassB,ClassC``, then multiple camelcase header files will be
generated which are redirects to the first header file.
The file locations of these generated headers will be stored in
<camelcase_forwarding_headers_var>.

ORIGINAL specifies how the name of the original header is written: lowercased
or also camelcased. The default is LOWERCASE. Since 1.8.0.

HEADER_EXTENSION specifies what file name extension is used for the header
files. The default is "h". Since 5.48.0.

PREFIX places the generated headers in subdirectories. This should be a
CamelCase name like ``KParts``, which will cause the CamelCase forwarding
headers to be placed in the ``KParts`` directory (e.g. ``KParts/Part``). It
will also, for the convenience of code in the source distribution, generate
forwarding headers based on the original names (e.g. ``kparts/part.h``). This
allows includes like ``"#include <kparts/part.h>"`` to be used before
installation, as long as the include_directories are set appropriately.

OUTPUT_DIR specifies where the files will be generated; this should be within
the build directory. By default, ``${CMAKE_CURRENT_BINARY_DIR}`` will be used.
This option can be used to avoid file conflicts.

REQUIRED_HEADERS specifies an output variable name where all the required
headers will be appended so that they can be installed together with the
generated ones. This is mostly intended as a convenience so that adding a new
header to a project only requires specifying the CamelCase variant in the
CMakeLists.txt file; the original variant will then be added to this
variable.

COMMON_HEADER generates an additional convenience header which includes all
other header files.

The RELATIVE argument indicates where the original headers can be found
relative to CMAKE_CURRENT_SOURCE_DIR. It does not affect the generated
CamelCase forwarding files, but quotient_generate_headers() uses it when checking
that the original header exists, and to generate originally named forwarding
headers when PREFIX is set.

To allow other parts of the source distribution (eg: tests) to use the
generated headers before installation, it may be desirable to set the
INCLUDE_DIRECTORIES property for the library target to output_dir. For
example, if OUTPUT_DIR is CMAKE_CURRENT_BINARY_DIR (the default), you could do

.. code-block:: cmake

target_include_directories(MyLib PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}>")

Example usage (without PREFIX):

.. code-block:: cmake

quotient_generate_headers(
MyLib_FORWARDING_HEADERS
HEADERS
MLFoo
MLBar
# etc
REQUIRED_HEADERS MyLib_HEADERS
COMMON_HEADER MLGeneral
)
install(FILES ${MyLib_FORWARDING_HEADERS} ${MyLib_HEADERS}
DESTINATION ${CMAKE_INSTALL_PREFIX}/include
COMPONENT Devel)

Example usage (with PREFIX):

.. code-block:: cmake

quotient_generate_headers(
MyLib_FORWARDING_HEADERS
HEADERS
Foo
# several classes are contained in bar.h, so generate
# additional files
Bar,BarList
# etc
PREFIX MyLib
REQUIRED_HEADERS MyLib_HEADERS
)
install(FILES ${MyLib_FORWARDING_HEADERS}
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/MyLib
COMPONENT Devel)
install(FILES ${MyLib_HEADERS}
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/mylib
COMPONENT Devel)

Since pre-1.0.0.
#]=======================================================================]

include(CMakeParseArguments)

function(QUOTIENT_GENERATE_HEADERS camelcase_forwarding_headers_var)
set(options)
set(oneValueArgs ORIGINAL HEADER_EXTENSION OUTPUT_DIR PREFIX REQUIRED_HEADERS COMMON_HEADER RELATIVE)
set(multiValueArgs HEADER_NAMES)
cmake_parse_arguments(EGH "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})

if (EGH_UNPARSED_ARGUMENTS)
message(FATAL_ERROR "Unexpected arguments to QUOTIENT_GENERATE_HEADERS: ${EGH_UNPARSED_ARGUMENTS}")
endif()

if(NOT EGH_HEADER_NAMES)
message(FATAL_ERROR "Missing header_names argument to QUOTIENT_GENERATE_HEADERS")
endif()

if(NOT EGH_ORIGINAL)
# default
set(EGH_ORIGINAL "LOWERCASE")
endif()
if(NOT EGH_ORIGINAL STREQUAL "LOWERCASE" AND NOT EGH_ORIGINAL STREQUAL "CAMELCASE")
message(FATAL_ERROR "Unexpected value for original argument to QUOTIENT_GENERATE_HEADERS: ${EGH_ORIGINAL}")
endif()

if(NOT EGH_HEADER_EXTENSION)
set(EGH_HEADER_EXTENSION "h")
endif()

if(NOT EGH_OUTPUT_DIR)
set(EGH_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}")
endif()

# Make sure EGH_RELATIVE is /-terminated when it's not empty
if (EGH_RELATIVE AND NOT "${EGH_RELATIVE}" MATCHES "^.*/$")
set(EGH_RELATIVE "${EGH_RELATIVE}/")
endif()

if (EGH_PREFIX)
if (NOT "${EGH_PREFIX}" MATCHES "^.*/$")
set(EGH_PREFIX "${EGH_PREFIX}/")
endif()
if (EGH_ORIGINAL STREQUAL "CAMELCASE")
set(originalprefix "${EGH_PREFIX}")
else()
string(TOLOWER "${EGH_PREFIX}" originalprefix)
endif()
endif()

foreach(_classnameentry ${EGH_HEADER_NAMES})
string(REPLACE "," ";" _classnames ${_classnameentry})
list(GET _classnames 0 _baseclass)

if (EGH_ORIGINAL STREQUAL "CAMELCASE")
set(originalbasename "${_baseclass}")
else()
string(TOLOWER "${_baseclass}" originalbasename)
endif()

set(_actualheader "${CMAKE_CURRENT_SOURCE_DIR}/${EGH_RELATIVE}${originalbasename}.${EGH_HEADER_EXTENSION}")
if (NOT EXISTS ${_actualheader})
message(FATAL_ERROR "Could not find \"${_actualheader}\"")
endif()

foreach(_CLASSNAME ${_classnames})
set(FANCY_HEADER_FILE "${EGH_OUTPUT_DIR}/${EGH_PREFIX}${_CLASSNAME}")
if (NOT EXISTS ${FANCY_HEADER_FILE})
file(WRITE ${FANCY_HEADER_FILE} "#include \"${originalprefix}${originalbasename}.${EGH_HEADER_EXTENSION}\"\n")
endif()
list(APPEND ${camelcase_forwarding_headers_var} "${FANCY_HEADER_FILE}")
if (EGH_PREFIX)
# Local forwarding header, for namespaced headers, e.g. kparts/part.h
if(EGH_ORIGINAL STREQUAL "CAMELCASE")
set(originalclassname "${_CLASSNAME}")
else()
string(TOLOWER "${_CLASSNAME}" originalclassname)
endif()
set(REGULAR_HEADER_NAME ${EGH_OUTPUT_DIR}/${originalprefix}${originalclassname}.${EGH_HEADER_EXTENSION})
if (NOT EXISTS ${REGULAR_HEADER_NAME})
file(WRITE ${REGULAR_HEADER_NAME} "#include \"${_actualheader}\"\n")
endif()
endif()
endforeach()

list(APPEND _REQUIRED_HEADERS "${_actualheader}")
endforeach()

if(EGH_COMMON_HEADER)
#combine required headers into 1 big convenience header
set(COMMON_HEADER ${EGH_OUTPUT_DIR}/${EGH_PREFIX}${EGH_COMMON_HEADER})
file(WRITE ${COMMON_HEADER} "// convenience header\n")
foreach(_header ${_REQUIRED_HEADERS})
get_filename_component(_base ${_header} NAME)
file(APPEND ${COMMON_HEADER} "#include \"${_base}\"\n")
endforeach()
list(APPEND ${camelcase_forwarding_headers_var} "${COMMON_HEADER}")
endif()

set(${camelcase_forwarding_headers_var} ${${camelcase_forwarding_headers_var}} PARENT_SCOPE)
if (NOT EGH_REQUIRED_HEADERS STREQUAL "")
set(${EGH_REQUIRED_HEADERS} ${${EGH_REQUIRED_HEADERS}} ${_REQUIRED_HEADERS} PARENT_SCOPE)
endif ()
endfunction()
117 changes: 117 additions & 0 deletions lib/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
set(Quotient_HEADERS
avatar.h
connection.h
connectiondata.h
converters.h
eventitem.h
e2ee.h
logging.h
encryptionmanager.h
networkaccessmanager.h
networksettings.h
qt_connection_util.h
quotient_common.h
settings.h
joinstate.h
ssosession.h
syncdata.h
user.h
uri.h
uriresolver.h
util.h

# jobs
jobs/basejob.h
jobs/syncjob.h
jobs/requestdata.h
jobs/downloadfilejob.h
jobs/mediathumbnailjob.h

# events
events/event.h
events/accountdataevents.h
events/callanswerevent.h
events/callcandidatesevent.h
events/callhangupevent.h
events/callinviteevent.h
events/directchatevent.h
events/encryptedevent.h
events/eventcontent.h
events/eventloader.h
events/reactionevent.h
events/receiptevent.h
events/redactionevent.h
events/roomevent.h
events/roomkeyevent.h
events/roomavatarevent.h
events/roomcreateevent.h
events/roomcanonicalaliasevent.h
events/roompowerlevelsevent.h
events/roommessageevent.h
events/roomtombstoneevent.h
events/simplestateevents.h
events/stateevent.h
events/stickerevent.h
events/typingevent.h
)

quotient_generate_headers(
QUOTIENT_FORWARDING_HEADERS
HEADER_NAMES
Room,FileTransferInfo,MemberSorter
Converters
Connection,LoginFlows
ConnectionData
EncryptionManager
EventItem,EventItemBase,EventStatus,TimelineItem
JoinState
Avatar
Logging
SyncData,RoomSummary,SyncRoomData
SsoSession
Settings
Uri
User
UriResolver,UriResolverBase,UriDispatcher,
Util
Jobs/BaseJob
Jobs/SyncJob
Jobs/RequestData
Jobs/MediaThumbnailJob
Jobs/DownloadFileJob
Events/Event
Events/AccountDataEvents
Events/CallAnswerEvent
Events/CallCandidatesEvent
Events/CallHangupEvent
Events/CallInviteEvent
Events/DirectChatEvent
Events/EncryptedEvent
Events/EventContent
Events/EventLoader
Events/ReactionEvent
Events/ReceiptEvent
Events/RedactionEvent
Events/RoomEvent
Events/RoomKeyEvent
Events/RoomAvatarEvent
Events/RoomCreateEvent
Events/RoomCanonicalAliasEvent
Events/RoomPowerLevelsEvent
Events/RoomMessageEvent
Events/RoomTombstoneEvent
Events/SimpleStateEvents
Events/StateEvent
Events/StickerEvent
Events/TypingEvent
PREFIX Quotient
REQUIRED_HEADERS Quotient_HEADERS
)
install(FILES ${QUOTIENT_FORWARDING_HEADERS}
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/Quotient
COMPONENT Devel)

install(FILES ${Quotient_HEADERS}
DESTINATION ${CMAKE_INSTALL_PREFIX}/include/quotient
COMPONENT Devel)