Pregunta

Mi colega afirma que deberíamos diseccionar nuestra aplicación C ++ (C ++, Linux) en bibliotecas compartidas para mejorar la modularidad, la capacidad de prueba y la reutilización del código.

Desde mi punto de vista, es una carga ya que el código que escribimos no necesita compartirse entre las aplicaciones en la misma máquina ni cargarse o descargarse dinámicamente y simplemente podemos vincular una aplicación ejecutable monolítica.

Además, envolver clases de C ++ con interfaces de función C en mi humilde opinión lo hace más feo.

También creo que la aplicación de un solo archivo será mucho más fácil de actualizar de forma remota en el sitio de un cliente.

¿Deben usarse las bibliotecas dinámicas cuando no hay necesidad de compartir código binario entre aplicaciones y sin carga de código dinámico?

¿Fue útil?

Solución

Diría que dividir el código en bibliotecas compartidas para mejorar sin tener un objetivo inmediato en mente es una señal de un entorno de desarrollo infestado de palabras de moda. Es mejor escribir código que se pueda dividir fácilmente en algún momento.

Pero, ¿por qué necesitaría envolver las clases de C ++ en interfaces de funciones C, excepto, tal vez, para la creación de objetos?

Además, dividirse en bibliotecas compartidas aquí suena como una mentalidad de lenguaje interpretado. En los lenguajes compilados, intenta no posponer hasta el tiempo de ejecución lo que puede hacer en tiempo de compilación. La vinculación dinámica innecesaria es exactamente el caso.

Otros consejos

Hacer cumplir las bibliotecas compartidas asegura que las bibliotecas no tengan dependencias circulares. El uso de bibliotecas compartidas a menudo conduce a un enlace más rápido y los errores de enlace se descubren en una etapa anterior que si no hay ningún enlace antes de que se vincule la aplicación final. Si desea evitar el envío de múltiples archivos a los clientes, puede considerar vincular la aplicación dinámicamente en su entorno de desarrollo y de forma estática al crear versiones de lanzamiento.

EDITAR: Realmente no veo una razón por la que necesite ajustar sus clases de C ++ usando interfaces C: esto se hace detrás de escena. En Linux puede usar bibliotecas compartidas sin ningún manejo especial. Sin embargo, en Windows, necesitaría ___ declspec (exportar) y ___ declspec (importar).

¿Mejorar la reutilización aunque no haya ninguna? No suena como un argumento fuerte.

La modularidad y la capacidad de prueba del código no necesitan depender de la unidad de implementación final. Esperaría que el enlace sea una decisión tardía.

Si realmente tiene una entregable y nunca anticipa ningún cambio, entonces suena como una exageración y una complejidad innecesaria para entregar en piezas.

Respuesta corta: no.

Respuesta más larga: las bibliotecas dinámicas no agregan nada que agregar a las pruebas, la modularidad o la reutilización que no se pueden hacer con la misma facilidad en una aplicación monolítica. El único beneficio que se me ocurre es que puede forzar la creación de una API en un equipo que no tiene la disciplina para hacerlo por su cuenta.

No hay nada mágico en una biblioteca (dinámica o de otro tipo). Si tiene todo el código para compilar una aplicación y una variedad de bibliotecas, puede compilarlo con la misma facilidad en un solo ejecutable.

En general, hemos descubierto que los costos de tener que lidiar con bibliotecas dinámicas no valen la pena a menos que exista una necesidad imperiosa (bibliotecas en múltiples aplicaciones, que necesitan actualizar varias aplicaciones sin recompilar, lo que permite al usuario agregar funciones a la aplicación).

Diseccionando los argumentos de su colega

Si cree que dividir su código en bibliotecas compartidas mejorará la modularidad, la capacidad de prueba y la reutilización del código, entonces supongo que esto significa que cree que tiene algunos problemas con su código y que hacer cumplir una "biblioteca compartida". la arquitectura lo corregirá.

¿Modularidad?

Su código debe tener interdependencias no deseadas que no habrían sucedido con una separación más limpia entre " código de biblioteca " y "codificar usando el código de la biblioteca".

Ahora, esto también se puede lograr a través de bibliotecas estáticas.

¿Pruebas?

Su código podría probarse mejor, tal vez creando pruebas unitarias para cada biblioteca compartida separada, automatizado en cada compilación.

Ahora, esto también se puede lograr a través de bibliotecas estáticas.

¿Reutilización de código?

A su colega le gustaría reutilizar un código que no está expuesto porque está oculto en las fuentes de su aplicación monolítica.

Conclusión

Los puntos 1 y 2 aún se pueden lograr con bibliotecas estáticas. Los 3 harían obligatorias las bibliotecas compartidas.

Ahora, si tiene más de una profundidad de vinculación de bibliotecas (estoy pensando en vincular dos bibliotecas estáticas que ya se compilaron para vincular las otras bibliotecas), esto puede ser complejo. En Windows, esto lleva a un error al vincular ya que algunas funciones (generalmente las funciones de tiempo de ejecución C / C ++, cuando se vinculan estáticamente) se mencionan más de una vez, y el compilador no puede elegir a qué función llamar. No sé cómo funciona esto en Linux, pero supongo que esto también podría suceder.

Diseccionando sus propios argumentos

Sus propios argumentos están algo sesgados:

¿Carga de compilación / vinculación de bibliotecas compartidas?

La carga de compilar y vincular a bibliotecas compartidas, en comparación con compilar y vincular a bibliotecas estáticas, no existe. Entonces este argumento no tiene valor.

¿Carga / descarga dinámicamente?

Cargar / descargar dinámicamente una biblioteca compartida podría ser un problema en un caso de uso muy limitado. En casos normales, el sistema operativo carga / descarga la biblioteca cuando es necesario sin su intervención, y de todos modos, sus problemas de rendimiento se encuentran en otro lugar.

¿Exponiendo código C ++ con interfaces C?

En cuanto al uso de una interfaz de función C para su código C ++, no entiendo: ya vincula las bibliotecas estáticas con una interfaz C ++. Vincular bibliotecas compartidas no es diferente.

Tendría un problema si tuviera compiladores diferentes para producir cada biblioteca de su aplicación, pero este no es el caso, ya que ya vincula sus bibliotecas estáticamente.

¿Un binario de un solo archivo es más fácil?

Tienes razón.

En Windows, la diferencia es despreciable, pero aún existe el problema de DLL Hell , que desaparece si agrega la versión a los nombres de su biblioteca o trabaja con Windows & nbsp; XP.

En Linux, además del problema de Windows anterior, tiene el hecho de que, de manera predeterminada, las bibliotecas compartidas deben estar en algunos directorios predeterminados del sistema para poder utilizarse, por lo que deberá copiarlas allí en la instalación (que puede ser una molestia ...) o cambiar algunas configuraciones predeterminadas del entorno (que también puede ser una molestia ...)

Conclusión: ¿Quién tiene razón?

Ahora, su problema no es "¿mi colega tiene razón?". Él es. Como eres tú también.

Su problema es:

  1. ¿Qué es lo que realmente quieres lograr?
  2. ¿Vale la pena el trabajo necesario para esta tarea?

La primera pregunta es muy importante, ya que me parece que sus argumentos y los argumentos de su colega están sesgados para llevar a la conclusión que parece más natural para cada uno de ustedes.

En otras palabras: cada uno de ustedes ya sabe cuál debería ser la solución ideal (de acuerdo con cada punto de vista) y cada uno de ustedes acumula argumentos para r

Haga un análisis simple de costo / beneficio: ¿realmente necesita modularidad, capacidad de prueba y reutilización? ¿Tiene tiempo para refactorizar su código para obtener esas funciones? Lo más importante, si refactoriza, ¿los beneficios que obtendrá justificarán el tiempo que llevó realizar la refactorización?

A menos que tenga problemas con las pruebas ahora, le recomiendo dejar su aplicación como está. La modularización es excelente, pero Linux tiene su propia versión de "DLL hell". (consulte ldconfig ), y ya ha indicado que la reutilización no es una necesidad.

Si está haciendo la pregunta y la respuesta no es obvia, entonces quédese donde está. Si no ha llegado al punto en el que la creación de una aplicación monolítica lleva demasiado tiempo o es demasiado difícil para su grupo trabajar juntos, entonces no hay una razón convincente para pasar a las bibliotecas. Puede crear un marco de prueba que funcione en los archivos de la aplicación si lo desea tal como está o simplemente puede crear otro proyecto que use los mismos archivos, pero adjunte una API de prueba y cree una biblioteca con eso.

Para fines de envío, si desea crear bibliotecas y enviar un gran ejecutable, siempre puede vincularlas estáticamente.

Si la modularidad ayudaría con el desarrollo, es decir, siempre estás en conflicto con otros desarrolladores sobre las modificaciones de archivos, entonces las bibliotecas pueden ayudar, pero eso tampoco es garantía. Usar un buen diseño de código orientado a objetos ayudará de todos modos.

Y no hay ninguna razón para ajustar las funciones con las interfaces C-invocables necesarias para crear una biblioteca a menos que desee que pueda invocarse desde C.

Las bibliotecas compartidas vienen con dolores de cabeza, pero creo que las bibliotecas compartidas son el camino correcto para llegar aquí. Yo diría que en la mayoría de los casos debería poder hacer que partes de su aplicación sean modulares y reutilizables en cualquier otro lugar de su negocio. Además, dependiendo del tamaño de este ejecutable monolítico, puede ser más fácil cargar un conjunto de bibliotecas actualizadas en lugar de un archivo grande.

En mi opinión, las bibliotecas en general conducen a un mejor código, un código más comprobable, y permite la creación de proyectos futuros de una manera más eficiente porque no reinventa la rueda.

En resumen, estoy de acuerdo con tu colega.

En Linux (y Windows) puede crear una biblioteca compartida usando C ++ y no tener que cargarla usando las exportaciones de la función C.

Es decir, construye classA.cpp en classA.so, y construye classB.cpp en classB (.exe) que enlaza con classA.so. Todo lo que realmente está haciendo es dividir su aplicación en múltiples archivos binarios. Esto tiene la ventaja de que son más rápidos de compilar, más fáciles de administrar y puede escribir aplicaciones que cargan solo ese código de biblioteca para probar.

Todo sigue siendo C ++, todo enlaza, pero su .so está separado de su aplicación enlazada estáticamente.

Ahora, si quisiera cargar un objeto diferente en tiempo de ejecución (es decir, no sabe cuál cargar hasta el tiempo de ejecución), entonces necesitaría crear un objeto compartido con exportaciones C, pero también será cargar esas funciones manualmente; no podrá utilizar el vinculador para hacer esto por usted.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top