在 cmake 中处理操作系统/平台特定代码
在我正在从事的多平台/操作系统项目中,我努力将特定于平台的代码简化到子目录中,并使用一个公共目录来保存公共实现。我在 autotools 中有一个原型实现,但如果可能的话想转向 cmake 实现。我目前的症结是如何支持多个操作系统。我当前的文件系统结构如下所示:
/* A common header file for all platforms that presents an interface */
include/my_socket_utils.h
include/my_time_utils.h
/* Platform specific source files */
src/common/my_socket_utils.cpp
src/linux/my_socket_utils.cpp
src/vxworks/my_socket_utils.cpp
src/qnx/my_socket_utils.cpp
src/common/my_time_utils.cpp
src/vxworks/my_time_utils.cpp
这个想法是有一个通用接口和一个“通用”实现。该实现可以是存根,也可以是按照 posix 标准编写的通用实现,使其适用于大多数平台。那些需要自定义实现的平台可以覆盖常见的实现,但它是可选的。
通过 autotools,我可以使用 VPATH 设置源树层次结构来实现此目的,因此我设置:
VPATH=@srcdir@/src/@target_platform@;@srcdir@/src/common
这使 autotools 首先在 src/@target_platform@ 中查找源文件,然后,如果找不到,则从src/公共。
cmake 的方法是什么?
更新: 为了帮助所有那些有需要的失落灵魂,这就是我目前所做的。我不确定这是最好的解决方案,但它效果很好。
FILE(GLOB common_files“src/common/.c”) FILE(GLOB platform_files "src/${os}/.c)
然后,执行肮脏的 n^2 算法来覆盖。不知道如何在 cmake “脚本”中做得更好,但是数量文件数量很少,因此速度很快,当然,诊断消息是可选的。
#
# For each common file, check to see if a platform file exists to override it.
#
foreach(fqfn ${common_files})
set(platform_override FALSE)
get_filename_component(filename ${fqfn} NAME)
#
# If filename exists in platform, override it with the platform,
# otherwise fall back to the common implementation. Oh for a real
# language.
#
foreach(platform_fqfn ${platform_files})
get_filename_component(platform_filename ${platform_fqfn} NAME)
message("pf=${platform_filename} cf=${filename}")
if(filename STREQUAL platform_filename)
message("filename == platform_filename")
list(APPEND proj_files ${platform_fqfn})
set(platform_override TRUE)
endif(filename STREQUAL platform_filename)
endforeach(platform_fqfn ${platform_files})
if(NOT ${platform_override})
list(APPEND proj_files ${fqfn})
message("Appended ${fqfn}")
endif(NOT ${platform_override})
endforeach(fqfn ${common_files})
message("proj_files=${proj_files}")
add_executable (cc_dfi_main ${proj_files})
In the multi-platform/os project I'm working on, I'm striving to simplify the platform specific code into subdirectories, with a common directory holding a common implementation. I have a prototype implementation in autotools, but want to move to a cmake implementation if possible. My current sticking point is how to support multiple OSes. My current filesystem structure looks like the following:
/* A common header file for all platforms that presents an interface */
include/my_socket_utils.h
include/my_time_utils.h
/* Platform specific source files */
src/common/my_socket_utils.cpp
src/linux/my_socket_utils.cpp
src/vxworks/my_socket_utils.cpp
src/qnx/my_socket_utils.cpp
src/common/my_time_utils.cpp
src/vxworks/my_time_utils.cpp
The idea is that there is a common interface and a "common" implementation. The implementation is either a stub or a common implementation written to a posix standard that allows it to work for most platforms. Those platforms that require a custom implementation MAY override the common one, but it's optional.
With autotools, I am able to achieve this using VPATH to set a source tree hierarchy, so I set:
VPATH=@srcdir@/src/@target_platform@;@srcdir@/src/common
This makes autotools look for the source file in src/@target_platform@ first, then, if it wasn't found, grab it from src/common.
What is the cmake way to do this?
Update:
To help all those lost souls in need, this is what I ended up doing for the time being. I'm not sure it's the best solution, but it works well enough.
FILE(GLOB common_files "src/common/.c")
FILE(GLOB platform_files "src/${os}/.c)
Then, do the dirty n^2 algorithm to override. Not sure how to do any better in cmake "script", but the number of files is low, so it's plenty fast. The diag messages are, of course, optional.
#
# For each common file, check to see if a platform file exists to override it.
#
foreach(fqfn ${common_files})
set(platform_override FALSE)
get_filename_component(filename ${fqfn} NAME)
#
# If filename exists in platform, override it with the platform,
# otherwise fall back to the common implementation. Oh for a real
# language.
#
foreach(platform_fqfn ${platform_files})
get_filename_component(platform_filename ${platform_fqfn} NAME)
message("pf=${platform_filename} cf=${filename}")
if(filename STREQUAL platform_filename)
message("filename == platform_filename")
list(APPEND proj_files ${platform_fqfn})
set(platform_override TRUE)
endif(filename STREQUAL platform_filename)
endforeach(platform_fqfn ${platform_files})
if(NOT ${platform_override})
list(APPEND proj_files ${fqfn})
message("Appended ${fqfn}")
endif(NOT ${platform_override})
endforeach(fqfn ${common_files})
message("proj_files=${proj_files}")
add_executable (cc_dfi_main ${proj_files})
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
一种可能的方法是定义变量
TARGET_BUILD_PLATFORM
并将其设置为您想要构建的确切平台 (linux/qnx/vxworks)。One possible way is to define variable
TARGET_BUILD_PLATFORM
and set it to exact platform you want to build (linux/qnx/vxworks).